package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.openea.perpartner.common.core.exception.ServiceException;
import cn.openea.perpartner.common.core.utils.DateUtils;
import cn.openea.perpartner.common.core.utils.IdWorker;
import cn.openea.perpartner.common.core.utils.StringUtils;
import cn.openea.perpartner.common.core.web.domain.AjaxResult;
import cn.openea.perpartner.meily.constant.CommonConstants;
import cn.openea.perpartner.meily.constant.enums.LogisticsModule;
import cn.openea.perpartner.meily.constant.enums.NotifySceneEnum;
import cn.openea.perpartner.meily.constant.enums.NotifySendEnum;
import cn.openea.perpartner.meily.thirdparty.WxPaySystemApi;
import cn.openea.perpartner.meily.thirdparty.notify.NotifySendEvent;
import cn.openea.perpartner.meily.web.entity.*;
import cn.openea.perpartner.meily.web.entity.dto.GoodsSalesDataDTO;
import cn.openea.perpartner.meily.web.entity.dto.GroupBuyingSubDTOFactory.SalesCommissionDTO;
import cn.openea.perpartner.meily.web.entity.dto.GroupDto;
import cn.openea.perpartner.meily.web.entity.vo.*;
import cn.openea.perpartner.meily.web.mapper.GroupBuyingSubMapper;
import cn.openea.perpartner.meily.web.service.*;
import cn.openea.perpartner.meily.web.service.logistics.businessModule.LogisticsModlueHandler;
import cn.openea.perpartner.meily.web.service.logistics.businessModule.LogisticsModuleService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * (GroupBuyingSub)表服务实现类
 *
 * @author rains
 * @since 2023-02-07 17:14
 */
@Slf4j
@Service("groupBuyingSubService")
public class GroupBuyingSubServiceImpl extends ServiceImpl<GroupBuyingSubMapper, GroupBuyingSub> implements IGroupBuyingSubService {

    @Value("${bpm.rest.url}")
    private String bpmUrl;
    @Value("${meily.header.sysid}")
    private String sysId;
    @Value("${meily.header.syspwd}")
    private String sysPwd;
    @Value("${bpm.msg_appid}")
    private String msgAppid;
    @Value("${bpm.msg_wf_num}")
    private String msgWfNum;
    @Value("${payment.order.authSalt}")
    private String authSalt;
    @Value("${payment.order.getTokenUrl}")
    private String getOrderSysTokenUrl;
    @Value("${payment.order.subPayToWallet}")
    private String subPayToWallet;
    @Value("${integral_sysytem_id}")
    private String INTEGRAL_SYSTEM_ID;
    @Value("${group.send_foreman_reward_timing}")
    private String sendForemanRewardTiming;
    @Value("${payment.coupon.usedCouponUrl}")
    private String usedCouponUrl;
    @Value("${payment.order.deductUrl}")
    private String deductUrl;

    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private WxPaySystemApi wxPaySystemApi;

    private IdWorker worker = new IdWorker(1, 1, 1);

    @Resource
    private IGroupBuyingService groupBuyingService;
    @Resource
    private IBuyingRecordService buyingRecordService;
    @Resource
    private IGoodsService goodsService;
    @Autowired
    private IProviderService providerService;
    @Resource
    private LogisticsModlueHandler logisticsModlueHandler;

    /** **************************** 以下是小程序使用到的 start lys *************************************** */

    /**
     * 是否可参与团购
     *
     * @param groupDto 实例对象
     * @return 是否可参与
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult canJoin(GroupDto groupDto) {

        if (StrUtil.isBlank(groupDto.getMainDocunid())) {
            return AjaxResult.error("获取不到mainDocunid，请检查参数是否有误！");
        }

        if (StrUtil.isBlank(groupDto.getPartnerId())) {
            return AjaxResult.error("获取不到partnerId，请检查参数是否有误！");
        }

        // 第0步 判断商品是否下架
        Goods goods = goodsService.getById(groupDto.getGoodsId());
        if ("已下架".equals(goods.getStatus())) {
            return AjaxResult.error("商品已下架，无法购买！");
        }

        // 直接购买，无需校验拼团限制
        if (groupDto.getMainDocunid().equals(groupDto.getGoodsId())) {
            return AjaxResult.success("可以参与！");
        }

        // 第1步 获取团购信息
        GroupBuying groupBuying = groupBuyingService.getById(groupDto.getMainDocunid());
        if (groupBuying == null || BeanUtil.isEmpty(groupBuying)) {
            return AjaxResult.error("根据主文档id(" + groupDto.getMainDocunid() + ")，找不到团购活动！");
        }

        // 第2步 判断此拼团是否已结束
        if ("2".equals(groupBuying.getStatus())) {
            return AjaxResult.error("拼团已结束，不可参与！");
        }

        // 第3步 判断是否可以参与拼团。【每人参与次数。0:不限；1:仅限一次；】
        if ("1".equals(groupBuying.getJoinNum())) {
            // 获取此拼团此用户的参与次数
            Long count = baseMapper.selectCount(new LambdaQueryWrapper<GroupBuyingSub>()
                    .eq(GroupBuyingSub::getMainDocunid, groupDto.getMainDocunid())
                    .eq(GroupBuyingSub::getPartnerId, groupDto.getPartnerId()));

            // 每人参与次数仅限一次，且已存在参与记录，则无法再次参与
            if (count == 1 || count > 1) {
                return AjaxResult.error("每人只能参与1次，您已参与，不可重复参与！");
            }
        }

        return AjaxResult.success("可以参与！");
    }

    /**
     * 参与团购
     * 步骤：
     * 1.保存参与团购记录；
     * 2.更新团购[主]任务一些字段;
     * 3.保存优惠券使用记录(2023-06-05 add);
     * 3.使用钱包余额进行抵扣(2023-06-15 add);
     * 4.保存订单记录(包含保存到订单系统)；
     * 5.给线上服务商发放分销报酬，以及发送订单通知；
     * 5.1 给线上服务商发放分销报酬（需要根据yml配置值判断是否需要在此发放）
     * 5.2 给线上服务商发放分销报酬成功后，修改字段： sendForemanReward = true（需要根据yml配置值判断是否需要在此发放）
     * 5.3 给线上服务商发放发送订单通知
     * 6.给服务商（包含代理服务商、选址服务商）发送订单通知。
     * 7.判断是否为区域服务商的首单
     *
     * @param groupBuyingSub 实例对象
     * @return 是否成功
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public AjaxResult join(GroupBuyingSub groupBuyingSub) throws ParseException {

        // 基本检验
        if (StrUtil.isBlank(groupBuyingSub.getPartnerId())) {
            throw new ServiceException("获取不到当前用户的userid，请检查是否登录！");
        }
        if (StrUtil.isBlank(groupBuyingSub.getPartnerName())) {
            throw new ServiceException("获取不到当前用户的userName，请检查是否登录！");
        }

        // 1.获取拼团详情
        GroupBuying groupBuying = groupBuyingService.getById(groupBuyingSub.getMainDocunid());
        if (groupBuying == null || BeanUtil.isEmpty(groupBuying)) {
            throw new ServiceException("根据文档id(" + groupBuyingSub.getMainDocunid() + ")，获取不到团购详情！");
        }

        // 2.获取商品信息
        Goods goods = goodsService.getById(groupBuyingSub.getGoodsId());
        if (goods == null || BeanUtil.isEmpty(goods)) {
            throw new ServiceException("根据商品id（" + groupBuyingSub.getGoodsId() + "）获取商品详情出错了");
        }

        /**
         * 第1步 保存参与团购记录
         */
        groupBuyingSub.setTaskNumber(String.valueOf(worker.nextId()));// 任务单号，全使用数字
        groupBuyingSub.setJoinTime(DateUtils.getNow());// 参与团购时间
        groupBuyingSub.setSupplyPrice(groupBuying.getSupplyPrice());// 供货价
        groupBuyingSub.setShippingLink(groupBuying.getShippingLink());// 发货链接
        groupBuyingSub.setGoodsBrand(groupBuying.getGoodsBrand());// 所属品牌
        groupBuyingSub.setGoodsCategory(goods.getCategory());// 商品分类
        groupBuyingSub.setGoodsType(goods.getGoodsType());// 商品类型

        // 商品规格
        if (StrUtil.isBlank(groupBuyingSub.getSpecification())) {
            groupBuyingSub.setSpecification(goods.getSpecification());
        }

        // 状态。0:未参与；1:已参与；(默认1)
        if (StrUtil.isBlank(groupBuyingSub.getStatus())) {
            groupBuyingSub.setStatus("1");
        }

        // 订单状态：已付款、已发货、已完成、已评价；(默认已付款)
        if (StrUtil.isBlank(groupBuyingSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus("已付款");
        }

        // 获取线上服务商信息信息(即拼团发起人)
        groupBuyingSub.setInitiatorId(groupBuying.getInitiatorId());// 线上服务商id
        groupBuyingSub.setInitiatorName(groupBuying.getInitiatorName());// 线上服务商昵称

        if (baseMapper.insert(groupBuyingSub) < 0) {
            throw new ServiceException("保存参与团购记录失败！");
        }

        // 生成分享验证id = 参与团购id + 3位随机数
        groupBuyingSub.setShareValidationId(groupBuyingSub.getId() + getRandomNumber(3));

        // 重新保存数据（分享验证id）
        if (!updateById(groupBuyingSub)) {
            throw new ServiceException("保存分享验证id失败！");
        }

        /**
         * 第2步 更新团购[主]任务一些字段
         */
        // 购买数量不为空，更新数据
        if (StrUtil.isNotBlank(groupBuyingSub.getBuyQuantity())) {
            // 更新已参与拼团的人数(原来的基础上加1)
            if (StrUtil.isNotBlank(groupBuying.getCustomerNum())) {
                int customerNum = Integer.parseInt(groupBuying.getCustomerNum()) + 1;
                groupBuying.setCustomerNum(Integer.toString(customerNum));
            }

            // 购买数量
            int buyQuantity = Integer.parseInt(groupBuyingSub.getBuyQuantity());

            // 更新已团购的商品数量
            if (StrUtil.isNotBlank(groupBuying.getUsedQuantity())) {
                int usedQuantity = Integer.parseInt(groupBuying.getUsedQuantity()) + buyQuantity;
                groupBuying.setUsedQuantity(Integer.toString(usedQuantity));
            }

            // 更新剩余的商品数量
            if (StrUtil.isNotBlank(groupBuying.getRemainQuantity())) {
                int remainQuantity = Integer.parseInt(groupBuying.getRemainQuantity()) - buyQuantity;
                groupBuying.setRemainQuantity(Integer.toString(remainQuantity));
            } else {
                int remainQuantity = Integer.parseInt(groupBuying.getTotalQuantity()) - buyQuantity;
                groupBuying.setRemainQuantity(Integer.toString(remainQuantity));
            }

            // 追加参与的拍档id
            if (StrUtil.isNotBlank(groupBuying.getJoinMember())) {
                HashSet<String> set = StringUtils.splitAsSet(groupBuying.getJoinMember());
                set.add(groupBuyingSub.getPartnerId());
                String JoinMember = StringUtils.join(set, ",");
                groupBuying.setJoinMember(JoinMember);
            }

            // 追加参与的拍档昵称
            if (StrUtil.isNotBlank(groupBuying.getJoinMemberShow())) {
                HashSet<String> set = StringUtils.splitAsSet(groupBuying.getJoinMemberShow());
                set.add(groupBuyingSub.getPartnerName());
                String JoinMemberShow = StringUtils.join(set, ",");
                groupBuying.setJoinMemberShow(JoinMemberShow);
            }

            // 追加参与团购的记录id
            if (StrUtil.isNotBlank(groupBuying.getAllSubDocunid())) {
                HashSet<String> set = StringUtils.splitAsSet(groupBuying.getAllSubDocunid());
                set.add(groupBuyingSub.getId());
                String AllSubDocunid = StringUtils.join(set, ",");
                groupBuying.setAllSubDocunid(AllSubDocunid);
            }

            // 更新时间
            groupBuying.setUpdateTime(DateUtil.now());

            if (!groupBuyingService.updateById(groupBuying)) {
                throw new ServiceException("更新团购信息失败！");
            }

        }

        /**
         * 2023-06-05 add
         * 第3步 保存优惠券使用记录
         */
        if (ObjectUtil.isNotEmpty(groupBuyingSub.getCouponId())) {
            JSONObject object = new JSONObject();
            object.put("userId", groupBuyingSub.getPartnerId());
            object.put("id", groupBuyingSub.getCouponId());
            object.put("couponId", groupBuyingSub.getCouponId());
            object.put("orderId", groupBuyingSub.getOrderId());
            object.put("orderMount", groupBuyingSub.getPayAmount());
            object.put("productId", groupBuyingSub.getGoodsId());
            object = getToken(object);
            JSONObject resObj = saveUsedCoupon(object);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("保存优惠券使用记录失败！");
            }
        }

        /**
         * 2023-06-15 add
         * 第3步 使用钱包余额进行抵扣
         */
        if ("1".equals(groupBuyingSub.getUseDeduction()) && groupBuyingSub.getDeductionAmount().compareTo(BigDecimal.ZERO) > 0) {
            JSONObject object = new JSONObject();
            object.put("userId", groupBuyingSub.getPartnerId());// 用户id
            object.put("coin", groupBuyingSub.getDeductionAmount());// 扣减金额
            object.put("reason", "购买" + groupBuyingSub.getGoodsName() + "时，使用钱包余额进行抵扣");// 原因
            object = getToken(object);
            JSONObject resObj = deduction(object);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("使用钱包余额进行抵扣：扣减钱包金额失败！");
            }
        }

        /**
         * 第4步 保存订单记录(包含保存到订单系统)；
         */
        BuyingRecord buyingRecord = new BuyingRecord();
        buyingRecord.setBuyerId(groupBuyingSub.getPartnerId());// 购买者id
        buyingRecord.setBuyerName(groupBuyingSub.getPartnerName());// 购买者昵称
        buyingRecord.setBuyerAvatarUrl(groupBuyingSub.getPartnerAvatarUrl());// 购买者头像
        buyingRecord.setBuyQuantity(groupBuyingSub.getBuyQuantity());// 购买数量
        buyingRecord.setUnitPrice(groupBuyingSub.getUnitPrice());// 商品单价
        buyingRecord.setPayAmount(groupBuyingSub.getPayAmount());// 支付金额
        buyingRecord.setGoodsId(groupBuyingSub.getGoodsId());// 商品记录唯一ID
        buyingRecord.setGoodsNo(groupBuyingSub.getGoodsNo());// 商品编号
        buyingRecord.setGoodsName(groupBuyingSub.getGoodsName());// 商品名称
        buyingRecord.setOrderNo(groupBuyingSub.getOrderId());// 订单编号
        buyingRecord.setSceneId(groupBuyingSub.getSceneId());// 场景ID
        buyingRecord.setSceneAssetsId(groupBuyingSub.getSceneAssetsId());// 定制ID
        buyingRecord.setCycle(groupBuyingSub.getCycle());// 周期串
        buyingRecord.setSourceId(groupBuyingSub.getMainDocunid());// 来源id(拼团主文档id或商品id)
        buyingRecord.setAddress(groupBuyingSub.getAddress());// 收货地址(JSONObject对象)
        buyingRecord.setSupplierId(groupBuyingSub.getSupplierId());// 供货商编号
        buyingRecord.setSupplierName(groupBuyingSub.getSupplierName());// 供货商名称
        buyingRecord.setSupplier(groupBuyingSub.getSupplier());// 供货商(JSONObject对象)
        buyingRecord.setOrderStatus("已支付");// 订单状态
        buyingRecord.setBuyTime(DateUtils.getNow());// 购买时间
        buyingRecord.setSpecification(groupBuyingSub.getSpecification());// 商品规则
        buyingRecord.setGroupBuyingSubId(groupBuyingSub.getId());// 业务关联id
        buyingRecord.setOrderRemarks(groupBuyingSub.getOrderRemarks());// 订单备注
        buyingRecord.setOriginalPayAmount(groupBuyingSub.getOriginalPayAmount());// 原来金额
        buyingRecord.setCouponId(groupBuyingSub.getCouponId());// 优惠券id
        buyingRecord.setCouponAmount(groupBuyingSub.getCouponAmount());// 优惠券金额
        buyingRecord.setUseDeduction(groupBuyingSub.getUseDeduction());// 是否使用抵扣
        buyingRecord.setDeductionAmount(groupBuyingSub.getDeductionAmount());// 抵扣金额
        if (!buyingRecordService.insert(buyingRecord)) {
            throw new ServiceException("保存订单记录失败！");
        }

        /**
         * 第5步 给线上服务商发放分销报酬；
         *      5.1 给线上服务商发放分销报酬（需要根据yml配置值判断是否需要在此发放）
         *      5.2 给线上服务商发放分销报酬成功后，修改字段： sendForemanReward = true（需要根据yml配置值判断是否需要在此发放）
         * 线上服务商分销报酬发放时机：buying:消费者下单成功后；receipt:消费者确认收货成功后。
         * sendForemanReward：是否发放线上服务商分销报酬。true:已发放；false:未发放
         */
        // 计算销售报酬（线上服务商分销报酬 * 购买数量）
        double _reward = 0.0;

        // 需要增加的积分 = 线上服务商分销报酬总额 * 100.0
        double points = 0.0;

        if (StrUtil.isNotBlank(groupBuyingSub.getBuyQuantity()) && StrUtil.isNotBlank(goods.getForemanReward())) {
            _reward = Double.parseDouble(groupBuyingSub.getBuyQuantity()) * Double.parseDouble(goods.getForemanReward());
            points = _reward * 100.0;
        }
        if ("buying".equals(sendForemanRewardTiming) && !Boolean.parseBoolean(groupBuyingSub.getSendForemanReward())) {
            if (_reward > 0 && points > 0) {
                // 5.1 给线上服务商发放分销报酬（调用积分系统：转入钱包）
                JSONObject object1 = new JSONObject();
                object1.put("userId", groupBuying.getInitiatorId());// 团长（拼团发起人id）
                object1.put("points", String.format("%.0f", points));// 保留0位小数
                object1.put("reason", groupBuying.getGoodsName() + "团购分销报酬，共" + String.format("%.2f", _reward) + "元");
                object1.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
                object1 = getToken(object1);
                JSONObject resObj = subPayToWallet(object1);
                if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                    log.error("消费者(" + groupBuyingSub.getPartnerId() + ")下单成功后，给线上服务商【" + groupBuying.getInitiatorName() + "(" + groupBuying.getInitiatorId() + ")" + "】发放分销报酬失败！购买记录：" + groupBuyingSub.getId());
                    throw new ServiceException("给线上服务商发放分销报酬失败！");
                }
            }

            // 5.2 给线上服务商发放分销报酬成功后，修改字段： sendForemanReward = true
            LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(GroupBuyingSub::getId, groupBuyingSub.getId());
            updateWrapper.set(GroupBuyingSub::getSendForemanReward, "true");
            updateWrapper.set(GroupBuyingSub::getUpdateTime, DateUtil.now());
            if (!update(updateWrapper)) {
                throw new ServiceException("更新数据出错了！");
            }

        }

        /**
         * 第6步 给服务商（包含代理服务商、选址服务商）发送订单通知。根据消费者身份发送通知
         * 情况1：当前消费者身份 = 消费者 + 代理服务商 + 选址服务商
         */
        String partnerId = groupBuyingSub.getPartnerId();// 消费者
        String initiatorId = groupBuyingSub.getInitiatorId();// 代理服务商（原线上服务商）
        String supplierId = groupBuyingSub.getSupplierId();// 选址服务商（原区域服务商）

        // 获取区域服务商编号
        JSONObject providerObject = JSONObject.parseObject(groupBuyingSub.getSupplier());
        String providerId = "";
        if (StrUtil.isNotBlank(providerObject.getString("providerId"))) {
            providerId = "N0." + providerObject.getString("providerId");
        }

        // 获取商品销量 = 商品自定义销量 + 实际销量
        GroupDto groupDto = new GroupDto();
        groupDto.setGoodsId(groupBuyingSub.getGoodsId());
        groupDto.setGoodsNo(groupBuyingSub.getGoodsNo());
        groupDto.setCycle(groupBuyingSub.getCycle());
        long goodsSalesVolume = buyingRecordService.getTotalSales(groupDto);

        // 分享报酬总额 = 消费者分享报酬 * 购买数量；
        double _consumerShareReward = 0.0;

        // 需要增加的积分 = 分享报酬总额 * 100.0
        double consumerSharePoints = 0.0;
        if (StrUtil.isNotBlank(goods.getConsumerShareReward()) && StrUtil.isNotBlank(groupBuyingSub.getBuyQuantity())) {
            _consumerShareReward = Double.parseDouble(goods.getConsumerShareReward()) * Double.parseDouble(groupBuyingSub.getBuyQuantity());
            consumerSharePoints = _consumerShareReward * 100.0;
        }

        /**
         * 情况一：自己开团自己购买
         *  1.1 选择自己作为供应商
         *  1.2 选择其他的供应商
         *
         * 情况二：
         *  2.1 参与别人的团，选择自己作为供应商 (参与者id != 发起人id) && (参与者id == 供应商id)
         *  2.2 参与别人的团，选择其他的供应商(参与者id != 发起人id) && (参与者id ！= 供应商id)
         *  2.3 参与别人的团，选择其他供应商时：
         *      2.3.1 发起人id == 供应商id
         *      2.3.2 发起人id ！= 供应商id
         */

        // 情况一：自己开团自己购买（参与者id == 发起人id）
        if (partnerId.equals(initiatorId)) {
            if (partnerId.equals(supplierId)) {
                // 1.1 选择自己作为供应商（参与者id == 发起人id == 供应商id）
                /*消费者+代理服务商+选址服务商：
                内容：【区域服务商NO.001】您所在的区域有新的订单，共1件商品，销售额9.90元，您获得3.30元销售佣金。
                订单编号：754958435349540305
                商品名称：百事可乐
                备注：点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【我的-代理销售商品列表】）*/
                HashMap<String, Object> paramsTrinity = new HashMap<>();
                paramsTrinity.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品，销售额" + groupBuyingSub.getPayAmount() + "元，您获得" + String.format("%.2f", _reward) + "元销售佣金。");
                paramsTrinity.put("keyword1", groupBuying.getTaskNumber());// 订单编号
                paramsTrinity.put("keyword2", groupBuying.getGoodsName());// 商品名称
                paramsTrinity.put("remark", "点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                paramsTrinity.put("pagepath", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                paramsTrinity.put("pageurl", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                paramsTrinity.put("docUnid", groupBuying.getId());
                paramsTrinity.put("userId", groupBuyingSub.getInitiatorId());
                JSONObject objectTrinity = sendMsg(paramsTrinity);
                if (objectTrinity.isEmpty() || !"200".equals(objectTrinity.getString("code"))) {
                    throw new ServiceException("情况一：给消费者+代理服务商+选址服务商发送订单通知失败！");
                }
            } else {
                // 1.2 选择其他的供应商（(参与者id == 发起人id) && (参与者id != 供应商id)）
                /*消费者+代理服务商：
                内容：您有新的订单，共1件商品，销售额9.90元，您获得3.30元销售佣金。
                订单编号：754958435349540305
                商品名称：百事可乐
                备注：点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【我的-代理销售商品列表】）*/
                HashMap<String, Object> paramsDiad = new HashMap<>();
                paramsDiad.put("first", "您有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品，销售额" + groupBuyingSub.getPayAmount() + "元，您获得" + String.format("%.2f", _reward) + "元销售佣金。");
                paramsDiad.put("keyword1", groupBuying.getTaskNumber());// 订单编号
                paramsDiad.put("keyword2", groupBuying.getGoodsName());// 商品名称
                paramsDiad.put("remark", "点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                paramsDiad.put("pagepath", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                paramsDiad.put("pageurl", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                paramsDiad.put("docUnid", groupBuying.getId());
                paramsDiad.put("userId", groupBuyingSub.getInitiatorId());
                JSONObject objectDiad = sendMsg(paramsDiad);
                if (objectDiad.isEmpty() || !"200".equals(objectDiad.getString("code"))) {
                    throw new ServiceException("情况一：给消费者+代理服务商发送订单通知失败！");
                }

                /*选址服务商：
                内容：【区域服务商NO.002】您所在的区域有新的订单，共1件商品。当前活动累计销量201件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！
                订单编号：754958435349540305
                商品名称：百事可乐
                备注：点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【生活-商品列表-商品销售详情】，即可开团的页面）*/
                HashMap<String, Object> paramsSupplier = new HashMap<>();
                paramsSupplier.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品。当前活动累计销量" + goodsSalesVolume + "件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！");
                paramsSupplier.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
                paramsSupplier.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
                paramsSupplier.put("remark", "点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                paramsSupplier.put("pagepath", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
                paramsSupplier.put("pageurl", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
                paramsSupplier.put("docUnid", groupBuyingSub.getId());
                paramsSupplier.put("userId", groupBuyingSub.getSupplierId());
                JSONObject objectSupplier = sendMsg(paramsSupplier);
                if (objectSupplier.isEmpty() || !"200".equals(objectSupplier.getString("code"))) {
                    throw new ServiceException("情况一：给选址服务商发送订单通知失败！");
                }
            }
        } else {
            // 情况二：参与别人的团（参与者id != 发起人id）
            if (partnerId.equals(supplierId)) {
                // 2.1 选择自己作为供应商 （(参与者id != 发起人id) && (参与者id == 供应商id)）
                /*消费者+选址服务商：
                内容：【区域服务商NO.001】您所在的区域有新的订单，共1件商品。当前活动累计销量201件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！
                订单编号：754958435349540305
                商品名称：百事可乐
                备注：点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【生活-商品销售详情】，即可开团的页面）*/
                HashMap<String, Object> paramsDiad2 = new HashMap<>();
                paramsDiad2.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品。当前活动累计销量" + goodsSalesVolume + "件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！");
                paramsDiad2.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
                paramsDiad2.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
                paramsDiad2.put("remark", "点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                paramsDiad2.put("pagepath", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
                paramsDiad2.put("pageurl", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
                paramsDiad2.put("docUnid", groupBuyingSub.getId());
                paramsDiad2.put("userId", groupBuyingSub.getSupplierId());
                JSONObject objectDiad2 = sendMsg(paramsDiad2);
                if (objectDiad2.isEmpty() || !"200".equals(objectDiad2.getString("code"))) {
                    throw new ServiceException("情况二：给消费者+选址服务商发送订单通知失败！");
                }
            } else {
                // 2.2 选择其他的供应商（(参与者id != 发起人id) && (参与者id ！= 供应商id)）
                /*消费者：
                内容：亲，请您核对订单信息，共1件商品消费9.90元，48小时内安排发货。完成平台分享任务还可获0.99元佣金～
                订单编号：754958435349540305
                商品名称：百事可乐
                备注：点击查看订单详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【我的-订单详情】）*/
                HashMap<String, Object> paramsPartner = new HashMap<>();
                paramsPartner.put("first", "亲，请您核对订单信息，共" + groupBuyingSub.getBuyQuantity() + "件商品消费" + groupBuyingSub.getPayAmount() + "元，48小时内安排发货。完成平台分享任务还可获" + String.format("%.2f", _consumerShareReward) + "元佣金～");
                paramsPartner.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
                paramsPartner.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
                paramsPartner.put("remark", "点击查看订单详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                paramsPartner.put("pagepath", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
                paramsPartner.put("pageurl", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
                paramsPartner.put("docUnid", groupBuyingSub.getId());
                paramsPartner.put("userId", groupBuyingSub.getPartnerId());
                JSONObject objectPartner = sendMsg(paramsPartner);
                if (objectPartner.isEmpty() || !"200".equals(objectPartner.getString("code"))) {
                    throw new ServiceException("情况二：给消费者发送订单通知失败！");
                }

                // 2.3 选择其他供应商时：
                if (initiatorId.equals(supplierId)) {
                    // 2.3.1 选择其他供应商时：发起人id == 供应商id
                    /*代理服务商+选址服务商：
                    内容：【区域服务商NO.002】您所在的区域有新的订单，共1件商品，销售额9.90元，您获得3.30元销售佣金。
                    订单编号：754958435349540305
                    商品名称：百事可乐
                    备注：点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【我的-代理销售商品列表】）*/
                    HashMap<String, Object> paramsDiad2 = new HashMap<>();
                    paramsDiad2.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品，销售额" + groupBuyingSub.getPayAmount() + "元，您获得" + String.format("%.2f", _reward) + "元销售佣金。");
                    paramsDiad2.put("keyword1", groupBuying.getTaskNumber());// 订单编号
                    paramsDiad2.put("keyword2", groupBuying.getGoodsName());// 商品名称
                    paramsDiad2.put("remark", "点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                    paramsDiad2.put("pagepath", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                    paramsDiad2.put("pageurl", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                    paramsDiad2.put("docUnid", groupBuying.getId());
                    paramsDiad2.put("userId", groupBuyingSub.getInitiatorId());
                    JSONObject objectDiad2 = sendMsg(paramsDiad2);
                    if (objectDiad2.isEmpty() || !"200".equals(objectDiad2.getString("code"))) {
                        throw new ServiceException("情况二：给代理服务商+选址服务商发送订单通知失败！");
                    }
                } else {
                    // 2.3.2 选择其他供应商时：发起人id ！= 供应商id
                    // 获取【发起人】的区域服务商编号
                    Provider provider = providerService.getByUserId(groupBuyingSub.getInitiatorId());
                    String initiatorProviderId = "";
                    if (provider != null) {
                        initiatorProviderId = "N0." + provider.getProviderId();
                    }

                    /*代理服务商：
                    内容：【区域服务商NO.002】您有新的订单，共1件商品，销售额9.90元，您获得3.30元销售佣金。
                    订单编号：754958435349540305
                    商品名称：百事可乐
                    备注：点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【我的-代理销售商品列表】）*/
                    HashMap<String, Object> paramsInitiator = new HashMap<>();
                    paramsInitiator.put("first", "【区域服务商" + initiatorProviderId + "】您有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品，销售额" + groupBuyingSub.getPayAmount() + "元，您获得" + String.format("%.2f", _reward) + "元销售佣金。");
                    paramsInitiator.put("keyword1", groupBuying.getTaskNumber());// 订单编号
                    paramsInitiator.put("keyword2", groupBuying.getGoodsName());// 商品名称
                    paramsInitiator.put("remark", "点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                    paramsInitiator.put("pagepath", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                    paramsInitiator.put("pageurl", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
                    paramsInitiator.put("docUnid", groupBuying.getId());
                    paramsInitiator.put("userId", groupBuyingSub.getInitiatorId());
                    JSONObject objectDiad2 = sendMsg(paramsInitiator);
                    if (objectDiad2.isEmpty() || !"200".equals(objectDiad2.getString("code"))) {
                        throw new ServiceException("情况二：给代理服务商发送订单通知失败！");
                    }

                    /*选址服务商：
                    内容：【区域服务商NO.003/004/...】您所在的区域有新的订单，共1件商品。当前活动累计销量201件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！
                    订单编号：754958435349540305
                    商品名称：百事可乐
                    备注：点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【生活-商品销售详情】，即可开团的页面）*/
                    HashMap<String, Object> paramsSupplier = new HashMap<>();
                    paramsSupplier.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品。当前活动累计销量" + goodsSalesVolume + "件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！");
                    paramsSupplier.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
                    paramsSupplier.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
                    paramsSupplier.put("remark", "点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
                    paramsSupplier.put("pagepath", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
                    paramsSupplier.put("pageurl", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
                    paramsSupplier.put("docUnid", groupBuyingSub.getId());
                    paramsSupplier.put("userId", groupBuyingSub.getSupplierId());
                    JSONObject objectSupplier = sendMsg(paramsSupplier);
                    if (objectSupplier.isEmpty() || !"200".equals(objectSupplier.getString("code"))) {
                        throw new ServiceException("情况二：给选址服务商发送订单通知失败！");
                    }
                }
            }
        }

        /**
         * 第7步 判断是否为区域服务商的首单
         * 条件：注册区域服务商24小时内，完成发起拼团，并下单，而且选择选择的区域服务商是自己
         */
        // 拼团发起人、参与者、区域服务商是同一人，才需要继续处理
        if (groupBuyingSub.getPartnerId().equals(groupBuyingSub.getSupplierId()) && groupBuyingSub.getPartnerId().equals(groupBuyingSub.getInitiatorId())) {

            // 区域服务商信息
            String createTime = providerObject.getString("createTime");// 注册时间

            if (StrUtil.isNotBlank(groupBuyingSub.getJoinTime()) && StrUtil.isNotBlank(createTime)) {
                // 判断注册时间与参与时间是否24小时内
                if (DateUtils.within24Hours(groupBuyingSub.getJoinTime(), createTime)) {
                    // 更新区域服务商的“首单状态”
                    LambdaUpdateWrapper<Provider> updateWrapper = new LambdaUpdateWrapper();
                    updateWrapper.eq(Provider::getId, providerObject.getString("id"));
                    updateWrapper.eq(Provider::getFirstOrderStatus, "未完成");

                    updateWrapper.set(Provider::getFirstOrderStatus, "已完成");
                    updateWrapper.set(Provider::getUpdateTime, DateUtil.now());
                    providerService.update(updateWrapper);
                }
            }
        }


        return AjaxResult.success("购买成功！", groupBuyingSub);
    }

    /**
     * 确认收货
     * 步骤：
     * 1.更新记录状态；
     * 2.给消费者发送订单完成通知；
     * 3.给线上服务商发放分销报酬：
     * 说明：不再需要根据yml配置值判断：
     * 只要是sendForemanReward = false都需要发放线上服务商发放分销报酬，
     * 且给线上服务商发放分销报酬成功后，修改字段： sendForemanReward = true
     * -----------------------------第4点 团销结算，暂不执行 2023-06-25 注释 by lys------------------------------------
     * 4.若拼团已结束才进行确认收货的，则需要发放团销奖励（消费者与线上服务商）；
     * 4.1 发放消费者团销返利；
     * 4.2 给消费者发送团销返利通知；
     * 4.3 发放线上服务商团销返利；
     * 4.4 更新“sendGroupSalesRewards = 'true'”；
     * 4.5 给线上服务商（代理服务商）发送团销返利通知；
     *
     * @param gbSub 实例对象
     * @return 更新结果
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public AjaxResult confirmReceipt(GroupBuyingSub gbSub) {
        if (StrUtil.isBlank(gbSub.getId())) {
            return AjaxResult.error("获取不到参与拼团记录的唯一id！");
        }

        GroupBuyingSub groupBuyingSub = getById(gbSub.getId());
        if (groupBuyingSub == null || BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.error("根据文档id(" + gbSub.getId() + ")，获取不到参与拼团记录详情！");
        }

        if ("已完成".equals(groupBuyingSub.getOrderStatus()) && StrUtil.isNotBlank(groupBuyingSub.getReceivingTime())) {
            return AjaxResult.error("您已确认收货，请勿重复操作！");
        }

        if ("已评价".equals(groupBuyingSub.getOrderStatus())) {
            return AjaxResult.error("您已确认收货，请勿重复操作！");
        }

        // 订单状态
        if (StrUtil.isNotBlank(gbSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus(gbSub.getOrderStatus());
        } else {
            groupBuyingSub.setOrderStatus("已完成");
        }

        // 收货时间
        if (StrUtil.isNotBlank(gbSub.getReceivingTime())) {
            groupBuyingSub.setReceivingTime(gbSub.getReceivingTime());
        } else {
            groupBuyingSub.setReceivingTime(DateUtil.now());
        }

        // 更新时间
        groupBuyingSub.setUpdateTime(DateUtil.now());

        /**
         * 第1步 更新记录状态
         */
        if (!updateById(groupBuyingSub)) {
            throw new ServiceException("确认收货失败！");
        }

        // 获取拼团详情
        GroupBuying gb = groupBuyingService.getById(groupBuyingSub.getMainDocunid());
        if (gb == null) {
            throw new ServiceException("获取不到拼团活动！");
        }

        String buyQuantity = groupBuyingSub.getBuyQuantity();// 购买数量
        String distributionReward = gb.getDistributionReward();// 线上服务商分销报酬（原团长帮卖报酬）

        // 线上服务商分销报酬总额 = 线上服务商分销报酬 * 购买数量；
        double _reward = 0.0;

        // 需要增加的积分 = 线上服务商分销报酬总额 * 100.0
        double points = 0.0;
        if (StrUtil.isNotBlank(distributionReward) && StrUtil.isNotBlank(buyQuantity)) {
            _reward = Double.parseDouble(distributionReward) * Double.parseDouble(buyQuantity);
            points = _reward * 100.0;
        }
        /**
         * 第3步 给线上服务商发放分销报酬
         * 只要是sendForemanReward = false都需要发放线上服务商发放分销报酬，
         * sendForemanReward：是否发放线上服务商分销报酬。true:已发放；false:未发放
         */
        if (!Boolean.parseBoolean(groupBuyingSub.getSendForemanReward())) {

            // 调用积分系统：转入钱包
            JSONObject obj = new JSONObject();
            obj.put("userId", gb.getInitiatorId());// 团长（拼团发起人id）
            obj.put("points", String.format("%.0f", points));// 保留0位小数
            obj.put("reason", groupBuyingSub.getGoodsName() + "团购分销报酬，共" + String.format("%.2f", _reward) + "元");
            obj.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
            obj = getToken(obj);
            JSONObject resObj = subPayToWallet(obj);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                log.error("消费者(" + groupBuyingSub.getPartnerId() + ")确认收货成功后，给线上服务商【" + gb.getInitiatorName() + "(" + gb.getInitiatorId() + ")" + "】发放分销报酬失败！购买记录：" + groupBuyingSub.getId());
                throw new ServiceException("给线上服务商发放分销报酬失败！");
            }

            /**
             * 第3.1步 给线上服务商发放分销报酬成功后，修改字段： sendForemanReward = true
             */
            LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(GroupBuyingSub::getId, groupBuyingSub.getId());
            updateWrapper.set(GroupBuyingSub::getSendForemanReward, "true");
            updateWrapper.set(GroupBuyingSub::getUpdateTime, DateUtil.now());
            if (!update(updateWrapper)) {
                throw new ServiceException("更新数据出错了！");
            }
        }

        /**
         * 第4步 若拼团已结束才进行确认收货的，则需要发放团销奖励（消费者与线上服务商）
         *  4.1 发放消费者团销返利；
         *  4.2 给消费者发送团销返利通知；
         *  4.3 发放线上服务商团销返利；
         *  4.4 更新“sendGroupSalesRewards = 'true'”
         *  4.5 给线上服务商（代理服务商）发送团销返利通知；
         */
        /**
         * 2023-06-25 注释 by lys
         * 注释原因：
         *  暂时不需要给消费者与线上服务商发放团销奖励与通知
         */
        /**
         * 2023-06-25 注释 by lys
         * 注释原因：
         *  暂时不需要给消费者与线上服务商发放团销奖励与通知

         // 获取订单完成情况
         JSONObject completionObject = getOrderCompletion(gb, gb.getDistributionReward());

         // 线上服务商团销报酬总额 = 线上服务商团销返利金额 * 购买数量；
         double online_reward = 0.0;

         // 线上服务商团销报酬需要增加的积分 = 线上服务商分销报酬总额 * 100.0
         double online_points = 0.0;

         // 消费者团销报酬总额 = 消费者团销返利金额 * 购买数量；
         double consumer_reward = 0.0;

         // 消费者团销报酬总额需要增加的积分 = 消费者团销报酬总额 * 100.0
         double consumer_points = 0.0;

         if ("2".equals(gb.getStatus())) {
         // 情况2：拼团已结束，需要计算团销返利金额并发放
         String consumerCashback = "";// 消费者返利金额
         String onlineCashback = "";// 线上服务商返利金额
         String groupType = "";// 团购类型。百人团/千人团/万人团

         // 1.获取此拼团商品购买总数（不包含自定义商品）
         // long totalBuyQuantity = getTotalBuyQuantity(gb.getGoodsId(), gb.getCycle(), gb.getId());
         // 1.获取商品总销量 = 实际销量 + 商品自定义销量
         GroupDto groupDto = new GroupDto();
         groupDto.setGoodsId(groupBuyingSub.getGoodsId());
         groupDto.setGoodsNo(groupBuyingSub.getGoodsNo());
         groupDto.setCycle(groupBuyingSub.getCycle());
         long totalBuyQuantity = buyingRecordService.getTotalSales(groupDto);

         if (totalBuyQuantity >= 100) {

         // 2.获取商品信息
         Goods goods = goodsService.getById(gb.getGoodsId());
         if (totalBuyQuantity > 100 && totalBuyQuantity <= 1000) {
         // 百人团
         consumerCashback = goods.getHundredConsumerCashback();
         onlineCashback = goods.getHundredOnlineCashback();
         groupType = "百人团";

         } else if (totalBuyQuantity > 1000 && totalBuyQuantity <= 10000) {
         // 千人团
         consumerCashback = goods.getThousandConsumerCashback();
         onlineCashback = goods.getThousandOnlineCashback();
         groupType = "千人团";

         } else if (totalBuyQuantity > 10000) {
         // 万人团
         consumerCashback = goods.getTenThousandConsumerCashback();
         onlineCashback = goods.getTenThousandOnlineCashback();
         groupType = "万人团";
         }

         // 消费者的团销返利总额
         if (StrUtil.isNotBlank(consumerCashback) && StrUtil.isNotBlank(buyQuantity)) {
         consumer_reward = Double.parseDouble(consumerCashback) * Double.parseDouble(buyQuantity);
         consumer_points = consumer_reward * 100.0;
         }
         // 线上服务商的团销返利总额
         if (StrUtil.isNotBlank(onlineCashback) && StrUtil.isNotBlank(buyQuantity)) {
         online_reward = Double.parseDouble(onlineCashback) * Double.parseDouble(buyQuantity);
         online_points = online_reward * 100.0;
         //                    if (!Boolean.parseBoolean(groupBuyingSub.getSendForemanReward())) {
         //                        _reward = online_reward + _reward;// 分销报酬+团销奖励
         //                    } else {
         //                        _reward = online_reward;// 团销奖励
         //                    }
         }
         }

         if (consumer_reward > 0 && consumer_points > 0) {
         // 1.发放消费者团销返利；
         JSONObject object = new JSONObject();
         object.put("userId", groupBuyingSub.getPartnerId());// 消费者id
         object.put("points", String.format("%.0f", consumer_points));// 保留0位小数
         object.put("reason", groupBuyingSub.getGoodsName() + "团购团销返利，共" + String.format("%.2f", consumer_reward) + "元");
         object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
         object = getToken(object);
         JSONObject resObj = subPayToWallet(object);
         if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
         throw new ServiceException("给已确认收货的消费者发放团销返利失败！");
         }

         // 2.发送消费者团销返利通知。
         HashMap<String, Object> params = new HashMap<>();
         params.put("first", "亲，本场活动已结束，活动累计总销量" + totalBuyQuantity + "件，已成" + groupType + "。您参与购买" + buyQuantity + "件商品，获返现" + String.format("%.2f", consumer_reward) + "元。");
         params.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
         params.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
         params.put("remark", "点击查看收益详情。平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
         params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
         params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
         params.put("docUnid", groupBuyingSub.getId());
         params.put("userId", groupBuyingSub.getPartnerId());
         JSONObject obj = sendMsg(params);
         if (!"200".equals(obj.getString("code"))) {
         throw new ServiceException("给已确认收货的消费者发送团销返利通知失败！");
         }
         }

         if (online_reward > 0 && online_points > 0) {
         // 3.发放线上服务商团销返利；
         JSONObject object2 = new JSONObject();
         object2.put("userId", groupBuyingSub.getInitiatorId());// 线上服务商id
         object2.put("points", String.format("%.0f", online_points));// 保留0位小数
         object2.put("reason", groupBuyingSub.getGoodsName() + "团购团销返利，共" + String.format("%.2f", online_reward) + "元");
         object2.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
         object2 = getToken(object2);
         JSONObject resObj2 = subPayToWallet(object2);
         if (resObj2.isEmpty() || !"200".equals(resObj2.getString("code"))) {
         throw new ServiceException("消费者确认收货后给线上服务商发放团销返利失败！");
         }
         }

         // 4.更新“sendGroupSalesRewards = 'true'”,是否发放团销奖励(消费者/线上服务商)。true:已发放；false:未发放
         LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.eq(GroupBuyingSub::getId, groupBuyingSub.getId());
         updateWrapper.set(GroupBuyingSub::getSendGroupSalesRewards, "true");
         updateWrapper.set(GroupBuyingSub::getUpdateTime, DateUtil.now());
         if (!update(updateWrapper)) {
         throw new ServiceException("更新sendGroupSalesRewards字段出错了！");
         }

         }

         //        代理服务商：
         //        内容：您有1个订单已确认收货，获得3.30元销售佣金并返利0.80元。仍有0个订单进行中！
         //        订单编号：754958435349540305
         //        商品名称：百事可乐
         //        备注：点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（链接到【我的-代理销售-代理销售商品列表】）
         String first = "您有1个订单已确认收货，获得" + String.format("%.2f", _reward) + "元销售佣金。";
         if ("2".equals(gb.getStatus())) {
         first += "并返利" + String.format("%.2f", online_reward) + "元。";
         }
         if (completionObject.getInteger("qutstandingOrderQuantity") > 0) {
         first += "仍有" + completionObject.getInteger("qutstandingOrderQuantity") + "个订单进行中！";
         }
         HashMap<String, Object> params2 = new HashMap<>();
         params2.put("first", first);
         params2.put("keyword1", gb.getTaskNumber());// 订单编号
         params2.put("keyword2", gb.getGoodsName());// 商品名称
         params2.put("remark", "点击查看销售进度。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
         params2.put("pagepath", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
         params2.put("pageurl", "/pages_tabbar_contact/personal_contact/SolitaireList");// （链接到【我的-代理销售-代理销售商品列表】）
         params2.put("docUnid", gb.getId());
         params2.put("userId", gb.getInitiatorId());
         JSONObject object2 = sendMsg(params2);
         if (object2.isEmpty() || !"200".equals(object2.getString("code"))) {
         throw new ServiceException("给代理服务商发送确认收货通知失败！");
         }*/

        return AjaxResult.success("确认收货成功！", groupBuyingSub);
    }

    /** **************************** 2023-05-04 add by lys start *************************************** */

    /**
     * 直接购买商品（即参与平台的团）
     * 步骤：
     * 1.保存参与团购记录；
     * 2.保存优惠券使用记录(2023-06-05 add);
     * 3.使用钱包余额进行抵扣(2023-06-15 add);
     * 4.保存订单记录(包含保存到订单系统)；
     * 5.发送订单通知。
     *
     * @param groupBuyingSub 实例对象
     * @return 是否成功
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public AjaxResult directPurchase(GroupBuyingSub groupBuyingSub) throws ParseException {

        /**
         * 第1步 保存参与团购记录；
         */

        // 2.获取商品信息
        Goods goods = goodsService.getById(groupBuyingSub.getGoodsId());
        if (goods == null || BeanUtil.isEmpty(goods)) {
            throw new ServiceException("根据商品id（" + groupBuyingSub.getGoodsId() + "）获取商品详情出错了");
        }

        groupBuyingSub.setTaskNumber(String.valueOf(worker.nextId()));// 任务单号，全使用数字
        groupBuyingSub.setJoinTime(DateUtils.getNow());// 参与团购时间
        groupBuyingSub.setShippingLink(goods.getShippingLink());// 发货链接
        groupBuyingSub.setGoodsBrand(goods.getBrand());// 所属品牌
        groupBuyingSub.setGoodsCategory(goods.getCategory());// 商品分类
        groupBuyingSub.setGoodsType(goods.getGoodsType());// 商品类型

        BigDecimal getSupplyPrice = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(goods.getSupplyPrice())) {
            getSupplyPrice = new BigDecimal(goods.getSupplyPrice().replaceAll("\\s", ""));
        }
        groupBuyingSub.setSupplyPrice(getSupplyPrice);// 供货价

        // 状态。0:未参与；1:已参与；(默认1)
        if (StrUtil.isBlank(groupBuyingSub.getStatus())) {
            groupBuyingSub.setStatus("1");
        }

        // 订单状态：已付款、已发货、已完成；(默认已付款)
        if (StrUtil.isBlank(groupBuyingSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus("已付款");
        }

        // 获取线上服务商信息信息(即平台)
        if (StrUtil.isBlank(groupBuyingSub.getInitiatorId())) {
            groupBuyingSub.setInitiatorId("meily");// 线上服务商id
        }

        if (StrUtil.isBlank(groupBuyingSub.getInitiatorName())) {
            groupBuyingSub.setInitiatorName("玫丽");// 线上服务商昵称
        }

        if (baseMapper.insert(groupBuyingSub) < 0) {
            return AjaxResult.error("保存参与团购记录出错了!");
        }

        /**
         * 2023-06-05 add
         * 第2步 保存优惠券使用记录
         */
        if (ObjectUtil.isNotEmpty(groupBuyingSub.getCouponId())) {
            JSONObject object = new JSONObject();
            object.put("userId", groupBuyingSub.getPartnerId());
            object.put("id", groupBuyingSub.getCouponId());
            object.put("couponId", groupBuyingSub.getCouponId());
            object.put("orderId", groupBuyingSub.getOrderId());
            object.put("orderMount", groupBuyingSub.getPayAmount());
            object.put("productId", groupBuyingSub.getGoodsId());
            object = getToken(object);
            JSONObject resObj = saveUsedCoupon(object);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("保存优惠券使用记录失败！");
            }
        }

        /**
         * 2023-06-15 add
         * 第3步 使用钱包余额进行抵扣
         */
        if ("1".equals(groupBuyingSub.getUseDeduction()) && groupBuyingSub.getDeductionAmount().compareTo(BigDecimal.ZERO) > 0) {
            JSONObject object = new JSONObject();
            object.put("userId", groupBuyingSub.getPartnerId());// 用户id
            object.put("coin", groupBuyingSub.getDeductionAmount());// 扣减金额
            object.put("reason", "购买" + groupBuyingSub.getGoodsName() + "时，使用钱包余额进行抵扣");// 原因
            object = getToken(object);
            JSONObject resObj = deduction(object);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("使用钱包余额进行抵扣：扣减钱包金额失败！");
            }
        }

        /**
         * 第4步 保存订单记录(包含保存到订单系统)；
         */
        BuyingRecord buyingRecord = new BuyingRecord();
        buyingRecord.setBuyerId(groupBuyingSub.getPartnerId());// 购买者id
        buyingRecord.setBuyerName(groupBuyingSub.getPartnerName());// 购买者昵称
        buyingRecord.setBuyerAvatarUrl(groupBuyingSub.getPartnerAvatarUrl());// 购买者头像
        buyingRecord.setBuyQuantity(groupBuyingSub.getBuyQuantity());// 购买数量
        buyingRecord.setUnitPrice(groupBuyingSub.getUnitPrice());// 商品单价
        buyingRecord.setPayAmount(groupBuyingSub.getPayAmount());// 支付金额
        buyingRecord.setGoodsId(groupBuyingSub.getGoodsId());// 商品记录唯一ID
        buyingRecord.setGoodsNo(groupBuyingSub.getGoodsNo());// 商品编号
        buyingRecord.setGoodsName(groupBuyingSub.getGoodsName());// 商品名称
        buyingRecord.setOrderNo(groupBuyingSub.getOrderId());// 订单编号
        buyingRecord.setSceneId(groupBuyingSub.getSceneId());// 场景ID
        buyingRecord.setSceneAssetsId(groupBuyingSub.getSceneAssetsId());// 定制ID
        buyingRecord.setCycle(groupBuyingSub.getCycle());// 周期串
        buyingRecord.setSourceId(groupBuyingSub.getMainDocunid());// 来源id(拼团主文档id或商品id)
        buyingRecord.setAddress(groupBuyingSub.getAddress());// 收货地址(JSONObject对象)
        buyingRecord.setSupplierId(groupBuyingSub.getSupplierId());// 供货商编号
        buyingRecord.setSupplierName(groupBuyingSub.getSupplierName());// 供货商名称
        buyingRecord.setSupplier(groupBuyingSub.getSupplier());// 供货商(JSONObject对象)
        buyingRecord.setOrderStatus("已支付");// 订单状态
        buyingRecord.setBuyTime(DateUtils.getNow());// 购买时间
        buyingRecord.setSpecification(groupBuyingSub.getSpecification());// 商品规则
        buyingRecord.setGroupBuyingSubId(groupBuyingSub.getId());// 业务关联id
        buyingRecord.setOrderRemarks(groupBuyingSub.getOrderRemarks());// 订单备注
        buyingRecord.setOriginalPayAmount(groupBuyingSub.getOriginalPayAmount());// 原来金额
        buyingRecord.setCouponId(groupBuyingSub.getCouponId());// 优惠券id
        buyingRecord.setCouponAmount(groupBuyingSub.getCouponAmount());// 优惠券金额
        buyingRecord.setUseDeduction(groupBuyingSub.getUseDeduction());// 是否使用抵扣
        buyingRecord.setDeductionAmount(groupBuyingSub.getDeductionAmount());// 抵扣金额
        if (!buyingRecordService.insert(buyingRecord)) {
            throw new ServiceException("保存订单记录失败！");
        }

        /**
         * 第5步 发送订单通知
         */
        // 获取商品总销量 = 实际销量 + 自定义销量
        GroupDto groupDto = new GroupDto();
        groupDto.setGoodsId(groupBuyingSub.getGoodsId());
        groupDto.setGoodsNo(groupBuyingSub.getGoodsNo());
        groupDto.setCycle(groupBuyingSub.getCycle());
        long goodsSalesVolume = buyingRecordService.getTotalSales(groupDto);

        // 获取区域商编号
        JSONObject providerObject = JSONObject.parseObject(groupBuyingSub.getSupplier());
        String providerId = "";
        if (StrUtil.isNotBlank(providerObject.getString("providerId"))) {
            providerId = "N0." + providerObject.getString("providerId");
        }

        // 分享报酬总额 = 消费者分享报酬 * 购买数量；
        double _consumerShareReward = 0.0;
        if (StrUtil.isNotBlank(goods.getConsumerShareReward()) && StrUtil.isNotBlank(groupBuyingSub.getBuyQuantity())) {
            _consumerShareReward = Double.parseDouble(goods.getConsumerShareReward()) * Double.parseDouble(groupBuyingSub.getBuyQuantity());
        }

        if (groupBuyingSub.getPartnerId().equals(groupBuyingSub.getSupplierId())) {
            // 消费者 = 供应商
            /*消费者+选址服务商：
            内容：【区域服务商NO.001】您所在的区域有新的订单，共1件商品。当前活动累计销量201件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！
            订单编号：754958435349540305
            商品名称：百事可乐
            备注：点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【生活-商品销售详情】，即可开团的页面）*/
            HashMap<String, Object> paramsDiad2 = new HashMap<>();
            paramsDiad2.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品。当前活动累计销量" + goodsSalesVolume + "件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！");
            paramsDiad2.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
            paramsDiad2.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
            paramsDiad2.put("remark", "点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
            paramsDiad2.put("pagepath", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
            paramsDiad2.put("pageurl", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
            paramsDiad2.put("docUnid", groupBuyingSub.getId());
            paramsDiad2.put("userId", groupBuyingSub.getSupplierId());
            JSONObject objectDiad2 = sendMsg(paramsDiad2);
            if (objectDiad2.isEmpty() || !"200".equals(objectDiad2.getString("code"))) {
                throw new ServiceException("情况二：给消费者+选址服务商发送订单通知失败！");
            }
        } else {
            /*消费者：
            内容：亲，请您核对订单信息，共1件商品消费9.90元，48小时内安排发货。完成平台分享任务还可获0.99元佣金～
            订单编号：754958435349540305
            商品名称：百事可乐
            备注：点击查看订单详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【我的-订单详情】）*/
            HashMap<String, Object> paramsPartner = new HashMap<>();
            paramsPartner.put("first", "亲，请您核对订单信息，共" + groupBuyingSub.getBuyQuantity() + "件商品消费" + groupBuyingSub.getPayAmount() + "元，48小时内安排发货。完成平台分享任务还可获" + String.format("%.2f", _consumerShareReward) + "元佣金～");
            paramsPartner.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
            paramsPartner.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
            paramsPartner.put("remark", "点击查看订单详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
            paramsPartner.put("pagepath", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
            paramsPartner.put("pageurl", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
            paramsPartner.put("docUnid", groupBuyingSub.getId());
            paramsPartner.put("userId", groupBuyingSub.getPartnerId());
            JSONObject objectPartner = sendMsg(paramsPartner);
            if (objectPartner.isEmpty() || !"200".equals(objectPartner.getString("code"))) {
                throw new ServiceException("给消费者发送订单通知失败！");
            }

            /*选址服务商：
            内容：【区域服务商NO.002】您所在的区域有新的订单，共1件商品。当前活动累计销量201件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！
            订单编号：754958435349540305
            商品名称：百事可乐
            备注：点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～（跳转到【生活-商品列表-商品销售详情】，即可开团的页面）*/
            HashMap<String, Object> paramsSupplier = new HashMap<>();
            paramsSupplier.put("first", "【区域服务商" + providerId + "】您所在的区域有新的订单，共" + groupBuyingSub.getBuyQuantity() + "件商品。当前活动累计销量" + goodsSalesVolume + "件，您所在的区域发现不少潜在消费者，建议代理销售商品赚取佣金！");
            paramsSupplier.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
            paramsSupplier.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
            paramsSupplier.put("remark", "点击查看商品详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
            paramsSupplier.put("pagepath", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
            paramsSupplier.put("pageurl", "/pages_private_scene2/GroupPurchase/DistributionGoods?goodsNo=" + groupBuyingSub.getGoodsNo() + "&goodsId=" + groupBuyingSub.getGoodsId());// （跳转到【生活-商品列表-商品销售详情】，即可开团的页面）
            paramsSupplier.put("docUnid", groupBuyingSub.getId());
            paramsSupplier.put("userId", groupBuyingSub.getSupplierId());
            JSONObject objectSupplier = sendMsg(paramsSupplier);
            if (objectSupplier.isEmpty() || !"200".equals(objectSupplier.getString("code"))) {
                throw new ServiceException("情况一：给选址服务商发送订单通知失败！");
            }
        }

        // 生成分享验证id = 参与团购id + 3位随机数
        groupBuyingSub.setShareValidationId(groupBuyingSub.getId() + getRandomNumber(3));

        // 重新保存数据（分享验证id）
        if (!updateById(groupBuyingSub)) {
            throw new ServiceException("保存分享验证id失败！");
        }

        return AjaxResult.success("购买成功！", groupBuyingSub);
    }

    /**
     * 直接购买商品-确认收货
     * 步骤：
     * 1.更新记录状态；
     * -----------------------------第2点 团销结算，暂不执行 2023-06-25 注释 by lys-------------------------------------
     * 2.给消费者发送订单完成通知；
     * 情况1：商品周期未结束，不做处理；
     * 情况2：商品周期已结束，需要计算团销返利金额发放，并发送通知，更新“sendGroupSalesRewards = 'true'”。
     *
     * @param gbSub 实例对象
     * @return 更新结果
     */
    @Override
    public AjaxResult confirmReceipt2(GroupBuyingSub gbSub) {
        if (StrUtil.isBlank(gbSub.getId())) {
            return AjaxResult.error("获取不到参与拼团记录的唯一id！");
        }

        GroupBuyingSub groupBuyingSub = getById(gbSub.getId());
        if (groupBuyingSub == null || BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.error("根据文档id(" + gbSub.getId() + ")，获取不到参与拼团记录详情！");
        }

        if ("已完成".equals(groupBuyingSub.getOrderStatus()) && StrUtil.isNotBlank(groupBuyingSub.getReceivingTime())) {
            return AjaxResult.error("您已确认收货，请勿重复操作！");
        }

        // 订单状态
        if (StrUtil.isNotBlank(gbSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus(gbSub.getOrderStatus());
        } else {
            groupBuyingSub.setOrderStatus("已完成");
        }

        // 收货时间
        if (StrUtil.isNotBlank(gbSub.getReceivingTime())) {
            groupBuyingSub.setReceivingTime(gbSub.getReceivingTime());
        } else {
            groupBuyingSub.setReceivingTime(DateUtil.now());
        }

        // 更新时间
        groupBuyingSub.setUpdateTime(DateUtil.now());

        /**
         * 第1步 更新记录状态
         */
        if (!updateById(groupBuyingSub)) {
            throw new ServiceException("确认收货失败！");
        }

        /**
         * 第2步 给消费者发送订单完成通知
         *  情况1：商品周期未结束，不做处理；
         *  情况2：商品周期已结束，需要计算团销返利金额发放，并发送通知，更新“sendGroupSalesRewards = 'true'”。
         */

        /**
         * 2023-06-25 注释 by lys
         * 注释原因：
         *  暂时不需要给消费者与线上服务商发放团销奖励与通知

         String currentCycle = goodsService.cycle(Long.parseLong(groupBuyingSub.getGoodsId()));// 当前周期
         boolean flag = false;// 当前周期是否大于历史周期。大于:true；小于:false；
         // 周期串如： 230052-1630915779874603010-1237643653
         if (StrUtil.isNotBlank(groupBuyingSub.getCycle()) && StrUtil.isNotBlank(currentCycle)) {
         String whichCycle = groupBuyingSub.getCycle().split("-")[0];
         String currentWhichCycle = currentCycle.split("-")[0];
         if (Integer.parseInt(currentWhichCycle) > Integer.parseInt(whichCycle)) {
         // 如果当前周期，大于历史周期，表示已经到了下个周期
         flag = true;
         }
         }

         if (currentCycle.equals(groupBuyingSub.getCycle()) && !flag) {
         // 周期串一样，则表示周期未结束
         System.out.println("商品周期未结束，无需发放团销奖励。");

         } else {
         // 情况2：商品周期已结束，需要计算团销返利金额并发放
         String consumerCashback = "";// 消费者返利金额
         String groupType = "";// 团购类型。百人团/千人团/万人团

         // 1.获取商品总销量 = 实际销量 + 商品自定义销量
         GroupDto groupDto = new GroupDto();
         groupDto.setGoodsId(groupBuyingSub.getGoodsId());
         groupDto.setGoodsNo(groupBuyingSub.getGoodsNo());
         groupDto.setCycle(groupBuyingSub.getCycle());
         long totalBuyQuantity = buyingRecordService.getTotalSales(groupDto);

         if (totalBuyQuantity >= 100) {

         // 2.获取商品信息
         Goods goods = goodsService.getById(groupBuyingSub.getGoodsId());
         if (totalBuyQuantity > 100 && totalBuyQuantity <= 1000) {
         // 百人团
         consumerCashback = goods.getHundredConsumerCashback();
         groupType = "百人团";

         } else if (totalBuyQuantity > 1000 && totalBuyQuantity <= 10000) {
         // 千人团
         consumerCashback = goods.getThousandConsumerCashback();
         groupType = "千人团";

         } else if (totalBuyQuantity > 10000) {
         // 万人团
         consumerCashback = goods.getTenThousandConsumerCashback();
         groupType = "万人团";
         }

         String buyQuantity = groupBuyingSub.getBuyQuantity();// 购买数量

         // 消费者团销报酬总额 = 消费者团销返利金额 * 购买数量；
         double consumer_reward = 0.0;

         // 消费者团销报酬总额需要增加的积分 = 消费者团销报酬总额 * 100.0
         double consumer_points = 0.0;

         // 消费者的团销返利总额
         if (StrUtil.isNotBlank(consumerCashback) && StrUtil.isNotBlank(buyQuantity)) {
         consumer_reward = Double.parseDouble(consumerCashback) * Double.parseDouble(buyQuantity);
         consumer_points = consumer_reward * 100.0;
         }

         if (consumer_reward > 0 && consumer_points > 0) {
         // 1.发放消费者团销返利；
         JSONObject object = new JSONObject();
         object.put("userId", groupBuyingSub.getPartnerId());// 消费者id
         object.put("points", String.format("%.0f", consumer_points));// 保留0位小数
         object.put("reason", groupBuyingSub.getGoodsName() + "团购团销返利，共" + String.format("%.2f", consumer_reward) + "元");
         object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
         object = getToken(object);
         JSONObject resObj = subPayToWallet(object);
         if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
         throw new ServiceException("给已确认收货的消费者发放团销返利失败！");
         }

         // 发送消费者团销返利通知。
         HashMap<String, Object> params = new HashMap<>();
         params.put("first", "亲，本场活动已结束，活动累计总销量" + totalBuyQuantity + "件，已成" + groupType + "。您参与购买" + buyQuantity + "件商品，获返现" + String.format("%.2f", consumer_reward) + "元。");
         params.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
         params.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
         params.put("remark", "点击查看收益详情。平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
         params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
         params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
         params.put("docUnid", groupBuyingSub.getId());
         params.put("userId", groupBuyingSub.getPartnerId());
         JSONObject obj = sendMsg(params);
         if (!"200".equals(obj.getString("code"))) {
         throw new ServiceException("给已确认收货的消费者发送团销返利通知失败！");
         }
         }

         // 3.更新“sendGroupSalesRewards = 'true'”,是否发放团销奖励(消费者/线上服务商)。true:已发放；false:未发放
         LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.eq(GroupBuyingSub::getId, groupBuyingSub.getId());
         updateWrapper.set(GroupBuyingSub::getSendGroupSalesRewards, "true");
         updateWrapper.set(GroupBuyingSub::getUpdateTime, DateUtil.now());
         if (!update(updateWrapper)) {
         throw new ServiceException("更新sendGroupSalesRewards字段出错了！");
         }

         }

         }*/

        return AjaxResult.success("确认收货成功！", groupBuyingSub);
    }

    /** **************************** 2023-05-04 add by lys end *************************************** */

    /**
     * 获取参与团购记录详情
     *
     * @param groupDto 实例对象
     * @return 查询结果
     */
    @Override
    public AjaxResult getOrderDetails(GroupDto groupDto) throws ParseException {

        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();

        // 如果参与记录唯一ID不为空，则直接根据此id查询，否则判断其他参数
        if (StrUtil.isNotBlank(groupDto.getRecordId())) {
            wrapper.eq(GroupBuyingSub::getId, groupDto.getRecordId());
        } else {
            if (StrUtil.isBlank(groupDto.getOrderId())) {
                return AjaxResult.error("获取不到orderId，请检查参数是否有误！");
            }

            if (StrUtil.isBlank(groupDto.getMainDocunid())) {
                return AjaxResult.error("获取不到mainDocunid，请检查参数是否有误！");
            }

            if (StrUtil.isBlank(groupDto.getGoodsNo())) {
                return AjaxResult.error("获取不到goodsNo，请检查参数是否有误！");
            }

            wrapper.eq(GroupBuyingSub::getOrderId, groupDto.getOrderId());
            wrapper.eq(GroupBuyingSub::getMainDocunid, groupDto.getMainDocunid());
            wrapper.eq(GroupBuyingSub::getGoodsNo, groupDto.getGoodsNo());
        }

        GroupBuyingSub groupBuyingSub = getOne(wrapper);
        if (groupBuyingSub == null || BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.success("根据参数找不到记录！", groupBuyingSub);
        }

        if ("已付款".equals(groupBuyingSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus("待发货");
        }
        if ("已发货".equals(groupBuyingSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus("待收货");
        }
        if ("已完成".equals(groupBuyingSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus("待评价");
        }

      /*  // 需要进行数据处理
        if ("已付款".equals(groupBuyingSub.getOrderStatus())) {
            groupBuyingSub.setOrderStatus("已付款，等待平台发货");
        }

        if ("已发货".equals(groupBuyingSub.getOrderStatus())) {

            // 根据发货时间，计算10天后的自动收货日期
            String enddate = DateUtils.plusDay(10, groupBuyingSub.getDeliveryTime());

            // 获取今天日期
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = new Date();
            String nowDate = sdf.format(date);

            // 计算 距离自动收货还差几天
            int diffValue = DateUtils.daysBetween(nowDate, enddate);

            groupBuyingSub.setOrderStatus("平台已发货<br>还有" + diffValue + "天自动确认");
        }*/

        return AjaxResult.success("获取参与记录(订单)详情成功！", groupBuyingSub);

    }

    /**
     * 获取参与团购记录列表---分页
     *
     * @param groupDto 实例对象
     * @return 查询结果
     */
    @Override
    public List<GroupBuyingSub> getJoinRecordList(GroupDto groupDto) throws ParseException {
        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(GroupBuyingSub::getMainDocunid, groupDto.getMainDocunid());
        if (StrUtil.isNotBlank(groupDto.getPartnerId())) {
            wrapper.eq(GroupBuyingSub::getPartnerId, groupDto.getPartnerId());
        }
        if (StrUtil.isNotBlank(groupDto.getSceneAssetsId())) {
            wrapper.eq(GroupBuyingSub::getSceneAssetsId, groupDto.getSceneAssetsId());
        }
        if (StrUtil.isNotBlank(groupDto.getSceneId())) {
            wrapper.eq(GroupBuyingSub::getSceneId, groupDto.getSceneId());
        }
        wrapper.orderByDesc(GroupBuyingSub::getCreateTime);

        List<GroupBuyingSub> list = list(wrapper);

        // 遍历结果，重新计算参与时间距离今天的间隔时间
        for (int i = 0; i < list.size(); i++) {
            GroupBuyingSub obj = list.get(i);
            obj.setJoinTime(DateUtils.getDiffTime(obj.getJoinTime()));
        }
        return list;
    }

    /**
     * 给消费者发放分享报酬（根据分享验证id）
     *
     * @param shareValidationId 分享验证id
     * @return 更新结果
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public AjaxResult sendShareRewardByVerificationId(String shareValidationId) {

        if (StrUtil.isBlank(shareValidationId)) {
            return AjaxResult.error("获取不到分享验证id！");
        }

        // 获取参与拼团记录详情
        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GroupBuyingSub::getShareValidationId, shareValidationId);
        GroupBuyingSub groupBuyingSub = getOne(wrapper);
        if (groupBuyingSub == null || BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.error("根据分享验证id(" + shareValidationId + ")，获取不到参与拼团记录详情！");
        }

        // 判断是否已发放了分享报酬。true:已发放
        String sendShareRewards = groupBuyingSub.getSendShareRewards();
        if (Boolean.parseBoolean(sendShareRewards)) {
            return AjaxResult.error("此分享报酬已发过，无需要重复发放！");
        }

        // 判断订单是否已结束（已申请退款）
        if ("已结束".equals(groupBuyingSub.getOrderStatus())) {
            return AjaxResult.error("此订单已申请退款，无需发放分享报酬！");
        }

        // 从商品信息中获取：分享报酬
        Goods goods = goodsService.getById(groupBuyingSub.getGoodsId());
        String consumerShareReward = goods.getConsumerShareReward();// 消费者分享报酬
        String buyQuantity = groupBuyingSub.getBuyQuantity();// 购买数量

        // 分享报酬总额 = 消费者分享报酬 * 购买数量；
        double _reward = 0.0;

        // 需要增加的积分 = 分享报酬总额 * 100.0
        double points = 0.0;
        if (StrUtil.isNotBlank(consumerShareReward) && StrUtil.isNotBlank(buyQuantity)) {
            _reward = Double.parseDouble(consumerShareReward) * Double.parseDouble(buyQuantity);
            points = _reward * 100.0;
        }

        // 调用积分系统：转入钱包
        JSONObject object = new JSONObject();
        object.put("userId", groupBuyingSub.getPartnerId());// 消费者id
        object.put("points", String.format("%.0f", points));// 保留0位小数
        object.put("reason", groupBuyingSub.getGoodsName() + "团购分享报酬，共" + String.format("%.2f", _reward) + "元");
        object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
        object = getToken(object);
        JSONObject resObj = subPayToWallet(object);
        if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
            throw new ServiceException("给消费者发放分享报酬失败！");
        }

        // 发放奖励成功，则更新信息
        groupBuyingSub.setSendShareRewards("true");// 已放分享报酬
        groupBuyingSub.setUpdateTime(DateUtil.now());// 更新时间

        if (!updateById(groupBuyingSub)) {
            throw new ServiceException("更新信息失败！");
        }

        // 更新信息成功，则发放通知
        HashMap<String, Object> params = new HashMap<>();
        params.put("first", "亲，您已完成3人分享任务，已获" + String.format("%.2f", _reward) + "奖励！");
        params.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
        params.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
        params.put("remark", "点击查看分享收益。");
        params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
        params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
        params.put("docUnid", groupBuyingSub.getId());
        params.put("userId", groupBuyingSub.getPartnerId());
        JSONObject obj = sendMsg(params);
        if (obj.isEmpty() || !"200".equals(obj.getString("code"))) {
            throw new ServiceException("给消费者发放分享报酬通知失败！");
        }

        return AjaxResult.success("给消费者发放分享报酬成功！");
    }

    /**
     * 保存分享图片路径
     *
     * @param object 实例对象
     * @return
     */
    @Transactional
    @Override
    public AjaxResult saveSharePictureUrl(JSONObject object) {
        if (StrUtil.isBlank(object.getString("shareValidationId"))) {
            return AjaxResult.error("获取不到参数shareValidationId！");
        }
        if (StrUtil.isBlank(object.getString("sharePictureUrl"))) {
            return AjaxResult.error("获取不到参数sharePictureUrl！");
        }

        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GroupBuyingSub::getShareValidationId, object.getString("shareValidationId"));
        GroupBuyingSub groupBuyingSub = getOne(wrapper);
        if (groupBuyingSub == null || BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.error("根据分享验证id(" + object.getString("shareValidationId") + ")，获取不到参与拼团记录！");
        }

        groupBuyingSub.setUpdateTime(DateUtil.now());// 更新时间
        groupBuyingSub.setSharePictureUrl(object.getString("sharePictureUrl"));// 分享图片路径
        if (!updateById(groupBuyingSub)) {
            throw new ServiceException("保存分享海报地址失败！");
        }

        return AjaxResult.success("保存分享海报地址成功！");
    }

    /**
     * 获取分享海报地址
     *
     * @param object 实例对象
     * @return
     */
    @Override
    public AjaxResult getharePictureUrl(JSONObject object) {

        if (StrUtil.isBlank(object.getString("shareValidationId"))) {
            return AjaxResult.error("获取不到参数shareValidationId！");
        }

        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GroupBuyingSub::getShareValidationId, object.getString("shareValidationId"));
        GroupBuyingSub groupBuyingSub = getOne(wrapper);
        if (groupBuyingSub == null || BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.error("获取分享海报地址失败！");
        }

        return AjaxResult.success("获取分享海报地址成功", groupBuyingSub.getSharePictureUrl());

    }

    /**
     * 首次打开分享发通知
     *
     * @param object 实例对象
     * @return
     */
    @Override
    public AjaxResult firstOpenShareSendMsg(JSONObject object) {

        if (StrUtil.isBlank(object.getString("shareValidationId"))) {
            return AjaxResult.error("获取不到分享验证id！");
        }
        if (StrUtil.isBlank(object.getString("completedTimes"))) {
            return AjaxResult.error("获取不到completedTimes！");
        }
        if (StrUtil.isBlank(object.getString("remainTimes"))) {
            return AjaxResult.error("获取不到remainTimes！");
        }

        // 获取参与拼团记录详情
        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GroupBuyingSub::getShareValidationId, object.getString("shareValidationId"));
        GroupBuyingSub groupBuyingSub = getOne(wrapper);

        if (BeanUtil.isEmpty(groupBuyingSub)) {
            return AjaxResult.error("根据分享验证id(" + object.getString("shareValidationId") + ")，获取不到参与拼团记录详情！");
        }

        // 从商品信息中获取：分享报酬
        Goods goods = goodsService.getById(groupBuyingSub.getGoodsId());
        String consumerShareReward = goods.getConsumerShareReward();// 消费者分享报酬
        String buyQuantity = groupBuyingSub.getBuyQuantity();// 购买数量

        // 分享报酬总额 = 消费者分享报酬 * 购买数量；
        double _reward = 0.0;

        if (StrUtil.isNotBlank(consumerShareReward) && StrUtil.isNotBlank(buyQuantity)) {
            _reward = Double.parseDouble(consumerShareReward) * Double.parseDouble(buyQuantity);
        }

        // 发放通知
        HashMap<String, Object> params = new HashMap<>();
        params.put("first", "亲，已有" + object.getString("completedTimes") + "名小伙伴查看商品，还差" + object.getString("remainTimes") + "人即可获得¥" + String.format("%.2f", _reward) + "分享奖励，加油哦～");
        params.put("keyword1", groupBuyingSub.getTaskNumber());// 订单编号
        params.put("keyword2", groupBuyingSub.getGoodsName());// 商品名称
        params.put("remark", "点击查看订单详情。");
        params.put("pagepath", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
        params.put("pageurl", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
        params.put("docUnid", groupBuyingSub.getId());
        params.put("userId", groupBuyingSub.getPartnerId());
        JSONObject obj = sendMsg(params);
        if (obj.isEmpty() || !"200".equals(obj.getString("code"))) {
            throw new ServiceException("首次打开分享发送通知执行失败！");
        }

        return AjaxResult.success("首次打开分享发送通知执行成功！");
    }

    /**
     * 保存评价
     *
     * @param groupBuyingSub 实例对象
     * @return
     */
    @Override
    public boolean saveEvaluation(GroupBuyingSub groupBuyingSub) {
        if (StrUtil.isBlank(groupBuyingSub.getId()) || StrUtil.isBlank(groupBuyingSub.getEvaluationContent())) {
            return false;
        }
        LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(GroupBuyingSub::getId, groupBuyingSub.getId());
        updateWrapper.set(GroupBuyingSub::getEvaluationContent, groupBuyingSub.getEvaluationContent());
        updateWrapper.set(GroupBuyingSub::getEvaluationPictures, groupBuyingSub.getEvaluationPictures());
        updateWrapper.set(GroupBuyingSub::getOrderStatus, "已评价");
        if (!update(updateWrapper)) {
            throw new ServiceException("保存评价出错了！");
        }
        return true;
    }

    /**
     * 获取用户当前周期已购买商品的数量
     *
     * @param groupBuyingSub
     * @return
     */
    @Override
    public long getQuantityByCurrentCycle(GroupBuyingSub groupBuyingSub) {
        QueryWrapper<GroupBuyingSub> queryWrapper = new QueryWrapper<>();
        StringBuffer queryStr = new StringBuffer();
        queryStr.append(" and partner_id = '" + groupBuyingSub.getPartnerId() + "'");
        queryStr.append(" and goods_id = '" + groupBuyingSub.getGoodsId() + "'");
        queryStr.append(" and goods_no = '" + groupBuyingSub.getGoodsNo() + "'");
        queryStr.append(" and cycle = '" + groupBuyingSub.getCycle() + "'");
        queryWrapper.last(" " + queryStr + " ");
        return baseMapper.getQuantityByCurrentCycle(queryWrapper);
    }

    /**
     * 保存退款信息
     *
     * @param object 实例对象
     * @return
     */
    @Override
    public AjaxResult saveRefundInfo(JSONObject object) {

        if (StrUtil.isBlank(object.getString("id"))) {
            return AjaxResult.error("获取不到参数id！");
        }

        if (StrUtil.isBlank(object.getString("refundNo"))) {
            return AjaxResult.error("获取不到参数refundNo！");
        }

        if (StrUtil.isBlank(object.getString("refundAmount"))) {
            return AjaxResult.error("获取不到参数refundAmount！");
        }

        if (StrUtil.isBlank(object.getString("orderStatus"))) {
            return AjaxResult.error("获取不到参数orderStatus！");
        }

        LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(GroupBuyingSub::getRefundNo, object.getString("refundNo"));// 退款订单号
        updateWrapper.set(GroupBuyingSub::getRefundAmount, object.getString("refundAmount"));// 退款金额
        updateWrapper.set(GroupBuyingSub::getRefundTime, DateUtil.now());// 退款时间
        updateWrapper.set(GroupBuyingSub::getOrderStatus, object.getString("orderStatus"));// 订单状态

        if (!update(updateWrapper)) {
            return AjaxResult.error("保存退款信息出错了!", getById(object.getString("id")));
        }

        return AjaxResult.success("保存退款信息成功", getById(object.getString("id")));
    }

    /**
     * 修改收货信息
     *
     * @param groupBuyingSub
     */
    @Override
    public AjaxResult modifyReceivingInfo(GroupBuyingSub groupBuyingSub) {
        if (StrUtil.isBlank(groupBuyingSub.getId())) {
            return AjaxResult.error("获取不到记录id！");
        }

        LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(GroupBuyingSub::getId, groupBuyingSub.getId());

        updateWrapper.set(GroupBuyingSub::getAddress, groupBuyingSub.getAddress());
        updateWrapper.set(GroupBuyingSub::getUpdateTime, DateUtil.now());

        if (!update(updateWrapper)) {
            throw new ServiceException("修改收货信息出错了！");
        }

        return AjaxResult.success("修改收货信息成功！");
    }

    /** **************************** 以上是小程序使用到的 end *************************************** */

    /** ********************* 以下结算团销返利使用的 start lys ******************************* */

    /**
     * 根据拼团主文档id获取所有参与团购记录-团销结算
     *
     * @param mainDocunid 拼团记录id
     * @return
     */
    @Override
    public List<GroupBuyingSub> getAllJoinList(String mainDocunid) {
        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GroupBuyingSub::getMainDocunid, mainDocunid);// 拼团记录id
        wrapper.orderByDesc(GroupBuyingSub::getCreateTime);
        return list(wrapper);
    }

    /**
     * 获取当前周期下某商品的所有购买记录-团销结算
     *
     * @param goodsId  商品id
     * @param cyclicId 周期串
     * @return
     */
    @Override
    public List<GroupBuyingSub> getAllBuyingList(String goodsId, String cyclicId) {
        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GroupBuyingSub::getGoodsId, goodsId);// 商品id
        wrapper.eq(GroupBuyingSub::getCycle, cyclicId);// 周期串
        wrapper.orderByDesc(GroupBuyingSub::getCreateTime);
        return list(wrapper);
    }

    /**
     * 获取购买商品数量-团销结算
     * 说明：如果传mainDocunid则表示获取当前拼团的，否则表示获取当前周期商品所有的
     *
     * @param goodsId     商品id
     * @param cyclicId    周期串
     * @param mainDocunid 拼团记录id
     * @return
     */
    @Override
    public long getTotalBuyQuantity(String goodsId, String cyclicId, String mainDocunid) {

        // 根据 周期串(必传)、商品id(必传)、主文档id(选填) 获取购买商品数量
        if (StrUtil.isBlank(goodsId) || StrUtil.isBlank(cyclicId)) {
            return 0;
        }

        QueryWrapper<GroupBuyingSub> queryWrapper = new QueryWrapper<>();

        StringBuffer queryStr = new StringBuffer();
        queryStr.append(" and goods_id = '" + goodsId + "'");
        queryStr.append(" and cycle = '" + cyclicId + "'");
        if (StrUtil.isNotBlank(mainDocunid)) {
            queryStr.append(" and main_docunid = '" + mainDocunid + "'");
        }

        queryWrapper.last(" " + queryStr + " ");

        return baseMapper.getTotalBuyQuantity(queryWrapper);
    }

    /**
     * 获取已完成的参与团购购买记录-团销结算
     *
     * @param goodsId     商品id
     * @param cyclicId    周期串
     * @param mainDocunid 拼团记录id
     * @return
     */
    @Override
    public List<GroupBuyingSub> getCompletedGroupRecordList(String goodsId, String cyclicId, String mainDocunid) {

        LambdaQueryWrapper<GroupBuyingSub> wrapper = new LambdaQueryWrapper<>();

        if (StrUtil.isNotBlank(goodsId)) {
            wrapper.eq(GroupBuyingSub::getGoodsId, goodsId);// 商品id
        }

        if (StrUtil.isNotBlank(cyclicId)) {
            wrapper.eq(GroupBuyingSub::getCycle, cyclicId);// 周期串
        }
        if (StrUtil.isNotBlank(mainDocunid)) {
            wrapper.eq(GroupBuyingSub::getMainDocunid, mainDocunid);// 拼团记录id
        }
        wrapper.in(GroupBuyingSub::getOrderStatus, "已完成", "已评价");
        // wrapper.eq(GroupBuyingSub::getOrderStatus, "已完成");
        wrapper.orderByDesc(GroupBuyingSub::getCreateTime);

        return list(wrapper);
    }

    /** ********************* 以上结算团销返利使用的  end lys ******************************* */

    /** ********************* 以下仅在后台使用到的 start lys ******************************* */
    /**
     * 获取拼团订单完成情况
     * 统计已完成、未完成、销售额
     *
     * @param groupBuying        拼团记录实体对象
     * @param distributionReward 线上服务商奖励
     */
    @Override
    public JSONObject getOrderCompletion(GroupBuying groupBuying, String distributionReward) {

        // 1.根据拼团主文档id获取所有参与团购记录
        List<GroupBuyingSub> allJoinList = getAllJoinList(groupBuying.getId());

        int completedOrderQuantity = 0;// 已完成订单数量
        long completedGoodsQuantity = 0;// 已完成订单的商品数量

        int qutstandingOrderQuantity = 0;// 未完成订单数量
        long qutstandingGoodsQuantity = 0;// 未完成订单的商品数量

        long totalOrderQuantity = 0;// 所有订单数量
        long totalGoodsQuantity = 0;// 所有订单的商品数量
        double completedReward = 0.00;// 实际收入 = (线上服务商分销佣金 * 购买商品数量) + (线上服务商百人团/千人团/万人团的团销报酬 * 购买商品数量)（拼团已结束才需要计算团销报酬）
        String onlineCashback = "";// 线上服务商百人团/千人团/万人团团销报酬

        if (distributionReward == null || StrUtil.isBlank(distributionReward)) {
            distributionReward = "0";
        }

        // 2.拼团已结束
        if ("2".equals(groupBuying.getStatus())) {
            // 1.获取此拼团商品实际销量（不包含商品自定义销量）
            long totalBuyQuantity = getTotalBuyQuantity(groupBuying.getGoodsId(), groupBuying.getCycle(), groupBuying.getId());

            // 2.线上服务商百人团/千人团/万人团团销报酬
            if (totalBuyQuantity >= 100) {
                // 2.获取商品信息
                Goods goods = goodsService.getById(groupBuying.getGoodsId());
                if (goods != null) {
                    if (totalBuyQuantity > 100 && totalBuyQuantity <= 1000) {
                        // 百人团
                        onlineCashback = goods.getHundredOnlineCashback();
                    } else if (totalBuyQuantity > 1000 && totalBuyQuantity <= 10000) {
                        // 千人团
                        onlineCashback = goods.getThousandOnlineCashback();
                    } else if (totalBuyQuantity > 10000) {
                        // 万人团
                        onlineCashback = goods.getTenThousandOnlineCashback();
                    }
                }
            }
        }

        // 3.遍历所有参与团购记录
        for (GroupBuyingSub gbSub : allJoinList) {
            // 是否发放线上服务商分销报酬。true:已发放；false:未发放
            if (Boolean.parseBoolean(gbSub.getSendForemanReward())) {
                completedReward += Double.parseDouble(distributionReward) * Long.parseLong(gbSub.getBuyQuantity());
            }

            if ("已完成".equals(gbSub.getOrderStatus()) || "已评价".equals(gbSub.getOrderStatus())) {
                completedOrderQuantity++;
                completedGoodsQuantity += Long.parseLong(gbSub.getBuyQuantity());
            } else {
                qutstandingOrderQuantity++;
                qutstandingGoodsQuantity += Long.parseLong(gbSub.getBuyQuantity());
            }
            totalOrderQuantity++;
            totalGoodsQuantity += Long.parseLong(gbSub.getBuyQuantity());

            // 情况2：拼团已结束：实际收入 = (线上服务商分销佣金 * 购买商品数量) + (线上服务商百人团/千人团/万人团的团销报酬 * 购买商品数量)
            if ("2".equals(groupBuying.getStatus())) {
                if (onlineCashback != null && StrUtil.isNotBlank(onlineCashback)) {
                    completedReward += Double.parseDouble(onlineCashback) * Long.parseLong(gbSub.getBuyQuantity());
                }
            }
        }

        if (Long.parseLong(groupBuying.getCustomerNum()) > totalOrderQuantity) {
            // TODO 说明被推广销售那边改动过
            // 订单数量一定是大于实际数量的
            Long addBuyQuantity = Long.parseLong(groupBuying.getUsedQuantity()) - totalGoodsQuantity;
            totalOrderQuantity = Long.parseLong(groupBuying.getCustomerNum());
            totalGoodsQuantity = Long.parseLong(groupBuying.getUsedQuantity());
            // 计算出新增的代理销售的佣金
            completedReward += Double.parseDouble(distributionReward) * addBuyQuantity;
        }

        JSONObject object = new JSONObject();

        object.put("completedOrderQuantity", completedOrderQuantity);// 已完成订单数量
        object.put("completedGoodsQuantity", completedGoodsQuantity);// 已完成订单的商品数量

        object.put("qutstandingOrderQuantity", qutstandingOrderQuantity);// 未完成订单数量
        object.put("qutstandingGoodsQuantity", qutstandingGoodsQuantity);// 未完成订单的商品数量

        object.put("totalOrderQuantity", totalOrderQuantity);// 所有订单数量
        object.put("totalGoodsQuantity", totalGoodsQuantity);// 所有订单的商品数量

//
        object.put("completedReward", String.format("%.2f", completedReward));// 实际收入


        return object;

    }

    /**
     * 获取分享标题
     *
     * @param groupBuying 拼团记录实体对象
     * @return
     */
    @Override
    public String getShareTitle(GroupBuying groupBuying) {

        String shareTitle = "";

        /*// 1.获取商品详情
        Goods goods = goodsService.getById(groupBuying.getGoodsId());
        if (goods == null || BeanUtil.isEmpty(goods)) {
            return shareTitle;
        }

        // 2.获取商品总销量 = 实际销量 + 商品自定义销量
        GroupDto groupDto = new GroupDto();
        groupDto.setGoodsId(groupBuying.getGoodsId());
        groupDto.setGoodsNo(groupBuying.getGoodsNo());
        groupDto.setCycle(groupBuying.getCycle());

        long totalSales = buyingRecordService.getTotalSales(groupDto);

        String consumerCashback = "0.00";// 消费者返利金额
        if (totalSales >= 100) {
            if (totalSales > 100 && totalSales <= 1000) {
                // 百人团
                consumerCashback = goods.getHundredConsumerCashback();
            } else if (totalSales > 1000 && totalSales <= 10000) {
                // 千人团
                consumerCashback = goods.getThousandConsumerCashback();
            } else if (totalSales > 10000) {
                // 万人团
                consumerCashback = goods.getTenThousandConsumerCashback();
            }
        }

        String consumerShareReward = "0.00";// 分享佣金
        if(StrUtil.isNotBlank(goods.getConsumerShareReward())){
            consumerShareReward = goods.getConsumerShareReward();
        }

        double reward = Double.parseDouble(consumerShareReward) + Double.parseDouble(consumerCashback);

        shareTitle = "最高返¥" + String.format("%.2f", reward) + "！！" + goods.getGoodsName();*/

        shareTitle = "[全网最低价]¥" + groupBuying.getUnitPrice() + "买" + groupBuying.getGoodsName();

        return shareTitle;
    }

    /**
     * 获取当前月已结束的拼团的所有参与记录
     *
     * @return
     */
    @Override
    public List<GroupBuyingSub> getCurrentMonthGroupFinishJoinList() {
        return baseMapper.getCurrentMonthGroupFinishJoinList();
    }

    /**
     * 获取上个月已结束的拼团的所有参与记录（不含当天）
     *
     * @return
     */
    @Override
    public List<GroupBuyingSub> getLastMonthGroupFinishJoinList() {
        return baseMapper.getLastMonthGroupFinishJoinList();
    }

    /** ********************* 以上仅在后台使用到的 end lys ******************************* */

    /** ********************* 以下调用其他系统的 start lys  ******************************* */

    /**
     * 获取token与authstr
     *
     * @param
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject getToken(JSONObject object) {
        HttpResponse resp = HttpRequest.post(getOrderSysTokenUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            JSONObject obj = JSON.parseObject(resp.body());
            String token = obj.getString("data");
            String tmpStr = authSalt.charAt(2) + authSalt.charAt(8) + token + authSalt.charAt(10) + authSalt.charAt(5);
            object.put("token", token);
            object.put("authStr", SecureUtil.md5(tmpStr));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return object;
    }

    /**
     * 积分系统：转入钱包
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject subPayToWallet(JSONObject object) {
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(subPayToWallet)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 积分系统：减扣钱包余额
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject deduction(JSONObject object) {

        System.out.println("********积分系统：减扣钱包余额*********");
        System.out.println("deductUrl=" + deductUrl);
        System.out.println("参数object=" + object);

        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(deductUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        System.out.println("返回结果=" + resp.body());
        System.out.println("*****************");
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 优惠券系统：保存优惠券使用记录
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject saveUsedCoupon(JSONObject object) {

        System.out.println("********优惠券系统：保存优惠券使用记录*********");
        System.out.println("usedCouponUrl=" + usedCouponUrl);
        System.out.println("参数object=" + object);

        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(usedCouponUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();

        System.out.println("返回结果=" + resp.body());

        System.out.println("*****************");
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 发送订单通知
     *
     * @param params 实例对象
     * @return
     */
    public JSONObject sendMsg(HashMap<String, Object> params) {
        JSONObject obj = new JSONObject();
        params.put("appid", msgAppid);
        params.put("wf_num", msgWfNum);
        HttpResponse resp = HttpRequest.post(bpmUrl)
                .header("sysid", sysId)
                .header("syspwd", sysPwd)
                .header("userId", "admin")
                .form(params)
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 获取随机数
     *
     * @param num 需要随机几位
     */
    private String getRandomNumber(int num) {

        String str = "ABCDEFGHIJKLMNOBQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder(num);

        for (int i = 0; i < num; i++) {
            char ch = str.charAt(new Random().nextInt(36));
            sb.append(ch);
        }

        return sb.toString();
    }

    @Override
    public List<GroupBuyingSub> selectByIds(List<String> batchIds) {
        if (batchIds == null || batchIds.isEmpty()) {
            return new ArrayList<>();
        }
        return baseMapper.selectBatchIds(batchIds);
    }

    /**
     * meily-购买记录分页查询
     *
     * @param recordVo
     * @return
     */
    @Override
    public List<GroupBuyingSub> selectList(OrderRecordVo recordVo) {
        if (recordVo == null) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<GroupBuyingSub> queryWrapper = buildGroupBuyingSubQueryWrapper(recordVo, true);
        return list(queryWrapper);
    }

    @Override
    public void logisticsChangeNotify(@NonNull GroupBuyingSub groupBuyingSub, Goods goods, String action) {
        if (goods == null) {
            throw new ServiceException("商品不能为空");
        }
        String first = "亲，您购买的商品物流信息有变，以此为准，请关注物流信息。完成品牌方指定分享任务可获报酬¥" + goods.getConsumerShareReward() + "！";
        if (CommonConstants.LOGISTICS.DELIVERY_ACTION.equals(action)) {
            first = "亲，您购买的商品已发货，请关注物流信息。完成品牌方指定分享任务可获报酬¥" + goods.getConsumerShareReward() + "！";
        }
        HashMap<String, Object> params = new HashMap<>();
        params.put("templateid", "YSKmMy3AhEkLu6uvOutdQxj7x76quLurxDlsTvGd-X8");
        params.put("first", first);
        params.put("keyword1", groupBuyingSub.getCourierName());// 快递公司
        params.put("keyword2", groupBuyingSub.getCourierNumber());// 快递单号
        params.put("keyword3", groupBuyingSub.getGoodsName());// 商品信息
        params.put("keyword4", groupBuyingSub.getBuyQuantity());// 商品数量
        params.put("remark", "点击查看订单详情。平台现有大量食品/美妆/洗护/母婴/百货商品销售资源，佣金非常可观，欢迎前来选品～");
        params.put("pagepath", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
        params.put("pageurl", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId=" + groupBuyingSub.getId());// （链接到【订单详情】）
        params.put("docUnid", groupBuyingSub.getId());
        params.put("userId", groupBuyingSub.getPartnerId());
        // 组建通知数据 TODO 这里有空在处理 将通知全部移动到事件中去
        Map<String, Object> data = new HashMap<>();
        data.put(NotifySendEnum.WX_PUBLIC_NUMBER.name(), params);
        String address = groupBuyingSub.getAddress();
        JSONObject addressObj = new JSONObject();
        if (StrUtil.isNotBlank(address)) {
            addressObj = JSONObject.parseObject(address);
        }
        data.put(NotifySendEnum.SMS.name(), GoodsDeliveryNoticeVo.builder()
                .sendTo(addressObj.getString("Name"))
                .phoneNumber(addressObj.getString("PhoneNum"))
                .commodity(goods.getGoodsName())
                .company(groupBuyingSub.getCourierName())
                .numbers(groupBuyingSub.getCourierNumber())
                .build());
        try {
            applicationContext.publishEvent(new NotifySendEvent(this,
                    NotifySendEnum.ALL,
                    NotifySceneEnum.GOODS_DELIVERY,
                    data));
        } catch (Exception e) {
            log.error("发送商品通知失败");
        }
    }

    /**
     * meily-团购订单数据更改
     *
     * @param editVo
     */
    @Override
    public void updateGroupBuyOrder(GroupBuyingSubEditVo editVo) {
        GroupBuyingSub groupBuyingSub = Optional.ofNullable(baseMapper.selectById(editVo.getId()))
                .orElseThrow(() -> new ServiceException("数据不存在"));
        LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = buildUpdateGroupBuyWrapper(editVo, groupBuyingSub);
        if (updateWrapper == null) {
            return;
        }
        update(updateWrapper);
    }

    /**
     * meily-更改订单收货地址
     *
     * @param id      id
     * @param address 收货地址 json串
     */
    @Override
    public void orderChangeAddress(String id, String address) {
        if (StringUtils.isBlank(id) || StringUtils.isBlank(address)) {
            throw new ServiceException("orderChangeAddress Method params id or address is blank");
        }
        LambdaUpdateWrapper<GroupBuyingSub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(GroupBuyingSub::getId, id);
        updateWrapper.set(GroupBuyingSub::getAddress, address);
        update(updateWrapper);
    }

    @Override
    public List<GroupBuyingSub> selectTestOrderList() {
        return baseMapper.selectList(new LambdaQueryWrapper<GroupBuyingSub>().eq(GroupBuyingSub::getEntity, "NO"));
    }

    @Override
    public Map<String, Integer> orderStatusCountQuery(OrderRecordVo recordVo) {
        if (recordVo == null) {
            return null;
        }
        recordVo.setOrderStatus("");
        return baseMapper.orderStatusCountQuery(buildGroupBuyingSubQueryWrapper(recordVo, false));
    }

    private LambdaQueryWrapper<GroupBuyingSub> buildGroupBuyingSubQueryWrapper(OrderRecordVo recordVo, boolean isSort) {
        LambdaQueryWrapper<GroupBuyingSub> queryWrapper = new LambdaQueryWrapper<>();
        if (recordVo.isFilterTestOrder()) {
            queryWrapper.eq(GroupBuyingSub::getEntity, "YES");
        }
        if (StringUtils.isNotBlank(recordVo.getOrderId())) {
            queryWrapper.eq(GroupBuyingSub::getOrderId, recordVo.getOrderId());
        }
        if (StringUtils.isNotBlank(recordVo.getExcludeOrderStatus())) {
            String excludeOrderStatus = recordVo.getExcludeOrderStatus();
            String[] excludeOrderStatusS = excludeOrderStatus.split(",");
            for (String exclude : excludeOrderStatusS) {
                queryWrapper.ne(GroupBuyingSub::getOrderStatus, exclude);
            }
        } else {
            if (StringUtils.isNotBlank(recordVo.getOrderStatus())) {
                queryWrapper.eq(GroupBuyingSub::getOrderStatus, recordVo.getOrderStatus());
            }
        }
        if (StringUtils.isNotBlank(recordVo.getCourierNumber())) {
            queryWrapper.eq(GroupBuyingSub::getCourierNumber, recordVo.getCourierNumber());
        }
        if (StringUtils.isNotBlank(recordVo.getGoodsNo())) {
            queryWrapper.eq(GroupBuyingSub::getGoodsNo, recordVo.getGoodsNo());
        }
        if (StringUtils.isNotBlank(recordVo.getProvidersName())) {
            queryWrapper.and(wrap -> {
                wrap.like(GroupBuyingSub::getInitiatorName, recordVo.getProvidersName())
                        .or()
                        .apply("supplier LIKE '%\"nickName\":\"" + recordVo.getProvidersName() + "%'")
                        .or()
                        .apply("supplier LIKE '%\"providerId\":\"" + recordVo.getProvidersName() + "%'");
            });
        }
        if (StringUtils.isNotBlank(recordVo.getConsigneeName())) {
            queryWrapper.apply("address LIKE '%\"Name\":\"" + recordVo.getConsigneeName() + "%'");
        }
        if (StringUtils.isNotBlank(recordVo.getConsigneePhone())) {
            queryWrapper.apply("address LIKE '%\"PhoneNum\":\"" + recordVo.getConsigneePhone() + "%'");
        }
        if (StringUtils.isNotBlank(recordVo.getGoodsName())) {
            queryWrapper.like(GroupBuyingSub::getGoodsName, recordVo.getGoodsName());
        }
        // 时间段查询
        String dateRange = recordVo.getDateRange();
        if (JSONUtil.isJson(dateRange)) {
            JSONObject jsonObject = JSON.parseObject(dateRange);
            String startDate = jsonObject.getString("startDate");
            String endDate = jsonObject.getString("endDate");
            if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
                // 比较两个时间的大小
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                if (LocalDate.parse(startDate, formatter).isAfter(LocalDate.parse(endDate, formatter))) {
                    throw new ServiceException("结束时间不能大于开始时间");
                }
                queryWrapper.apply("DATE(join_time) BETWEEN '" + startDate + "' AND '" + endDate + "'");
            }
        }
        if (isSort) {
            queryWrapper.orderByDesc(GroupBuyingSub::getJoinTime);
        }
        return queryWrapper;
    }

    @Override
    public List<GroupBuyingSub> selectByIdsAndOrderState(List<String> batchIds, String orderState) {
        if (batchIds == null || batchIds.isEmpty()) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<GroupBuyingSub> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GroupBuyingSub::getOrderStatus, orderState)
                .in(GroupBuyingSub::getId, batchIds);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<GoodsSalesDataDTO> salesStatisticsList(OrderSalesDataVo salesDataVo) {
        if (salesDataVo == null) {
            return new ArrayList<>();
        }
        salesDataVo.buildDateRangeParams();
        return baseMapper.goodSSalesDataList(salesDataVo);
    }

    @Override
    public Map<String, Object> statisticsAllGoodsSalesData(OrderSalesDataVo salesDataVo) {
        salesDataVo.buildDateRangeParams();
        return baseMapper.statisticsAllGoodsSalesData(salesDataVo);
    }

    @Override
    public GroupBuyingSub findByOrderId(String orderId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<GroupBuyingSub>()
                .eq(GroupBuyingSub::getOrderId, orderId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderDelayedReceipt(String id, Integer days) {
        if (StringUtils.isBlank(id)) {
            throw new ServiceException("id is blank");
        }
        GroupBuyingSub groupBuyingSub = Optional.ofNullable(getById(id))
                .orElseThrow(() -> new ServiceException("订单不存在"));

        if (!"已发货".equals(groupBuyingSub.getOrderStatus())) {
            throw new ServiceException("订单状态异常，请联系系统管理员");
        }

        // 过期时间 = 过期时间 + 延时收货天数
        String expirationTime = groupBuyingSub.getExpirationTime();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = DateUtils.addDays(sdf.parse(expirationTime), days);
            expirationTime = sdf.format(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        // 累加
        this.update(new LambdaUpdateWrapper<GroupBuyingSub>().eq(GroupBuyingSub::getId, id)
                .set(GroupBuyingSub::getDelayedReceiptDays, days + groupBuyingSub.getDelayedReceiptDays())
                .set(GroupBuyingSub::getExpirationTime, expirationTime));
        // 同时去更改物流那边保存的信息
        LogisticsModuleService service = logisticsModlueHandler.getService(LogisticsModule.GROUPBUY);
        service.businessDelayedReceipt(id, days);
    }

    @Override
    public List<GroupBuyingSub> findFortyEightHourData(OrderRecordVo recordVo) {
        recordVo.setOrderStatus("已发货");
        recordVo.setExcludeOrderStatus("");
        LambdaQueryWrapper<GroupBuyingSub> queryWrapper = buildGroupBuyingSubQueryWrapper(recordVo, true);
        queryWrapper.apply("delivery_time + INTERVAL (10 + meily_group_buying_sub.delayed_receipt_days) DAY > NOW() " +
                "AND delivery_time + INTERVAL (10 + meily_group_buying_sub.delayed_receipt_days) DAY < DATE_ADD(NOW(), INTERVAL 48 HOUR)");
        return baseMapper.selectList(queryWrapper);
    }

    private LambdaUpdateWrapper<GroupBuyingSub> buildUpdateGroupBuyWrapper(GroupBuyingSubEditVo editVo, GroupBuyingSub groupBuyingSub) {
        if (StringUtils.isBlank(editVo.getId()) || groupBuyingSub == null) {
            return null;
        }
        LambdaUpdateWrapper<GroupBuyingSub> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(GroupBuyingSub::getId, editVo.getId());
        if (StringUtils.isNotBlank(editVo.getMarkColor())) {
            lambdaUpdateWrapper.set(GroupBuyingSub::getMarkColor, editVo.getMarkColor());
        }
        if (editVo.getRealSupplyPrice() != null) {
            lambdaUpdateWrapper.set(GroupBuyingSub::getRealSupplyPrice, editVo.getRealSupplyPrice());
        }
        if (StringUtils.isNotBlank(editVo.getEntity())) {
            lambdaUpdateWrapper.set(GroupBuyingSub::getEntity, editVo.getEntity());
        }
        return lambdaUpdateWrapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refund(OrderRefundVo orderRefundVo) {
        GroupBuyingSub groupBuyingSub = Optional.ofNullable(getById(orderRefundVo.getId()))
                .orElseThrow(() -> new ServiceException("团购订单不存在"));
        if ("已退款".equals(groupBuyingSub.getOrderStatus())) {
            throw new ServiceException("改订单已退款，不可重复操作");
        }
//        SalesCommissionDTO salesCommissionDTO = findPurchaseCommissionDetailsById(groupBuyingSub);
        BigDecimal refundAmount = orderRefundVo.getRefundAmount();
//                .subtract(salesComTO.getConsumerShareReward())
////                .subtract(salesCommissionDTO.getForemanReward());·missionD
        // 计算出需要退款的金额 实付金额-分享佣金-代理销售佣金
        String refundNo = wxPaySystemApi.refund(refundAmount, groupBuyingSub);
        // 更改订单状态为已退款
        groupBuyingSub.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_UP).toString());
        groupBuyingSub.setRefundTime(DateUtils.getNow());
        groupBuyingSub.setRefundNo(refundNo);
        groupBuyingSub.setOrderStatus("已退款");
        baseMapper.updateById(groupBuyingSub);
        return !refundNo.equals(CommonConstants.PURSE_REFUND_FAILED);
    }

    @Override
    public SalesCommissionDTO findPurchaseCommissionDetailsById(GroupBuyingSub groupBuyingSub) {
        if (groupBuyingSub == null || StringUtils.isBlank(groupBuyingSub.getId())) {
            throw new ServiceException("团购不存在");
        }
        SalesCommissionDTO salesCommissionDTO = SalesCommissionDTO.builder()
                .id(groupBuyingSub.getId())
                .mainDocunid(groupBuyingSub.getMainDocunid())
                .partnerId(groupBuyingSub.getPartnerId())
                .orderId(groupBuyingSub.getOrderId())
                .orderStatus(groupBuyingSub.getOrderStatus())
                .payAmount(new BigDecimal(groupBuyingSub.getPayAmount()))
                .deductionAmount(groupBuyingSub.getDeductionAmount())
                .build();
        Goods goods = Optional.ofNullable(goodsService.findById(groupBuyingSub.getGoodsId()))
                .orElseThrow(() -> new ServiceException("商品不存在"));
        if ("true".equals(groupBuyingSub.getSendShareRewards())) {
            // 分享佣金
            salesCommissionDTO.setConsumerShareReward(new BigDecimal(goods.getConsumerShareReward()));
        }
        if ("true".equals(groupBuyingSub.getSendForemanReward())) {
            // 线上服务商分享报酬
            List<GroupBuyingSub> allJoinList = getAllJoinList(groupBuyingSub.getMainDocunid());
            BigDecimal foremanReward = new BigDecimal(goods.getForemanReward());
            salesCommissionDTO.setForemanReward(foremanReward.multiply(BigDecimal.valueOf(allJoinList.size())));
            // 获取团销报酬
            String consumerCashback = "0.00";// 消费者返现金额
            int totalSales = allJoinList.size();
            if (totalSales > 100 && totalSales <= 1000) {
                // 百人团
                consumerCashback = goods.getHundredConsumerCashback();

            } else if (totalSales > 1000 && totalSales <= 10000) {
                // 千人团
                consumerCashback = goods.getThousandConsumerCashback();

            } else if (totalSales > 10000) {
                // 万人团
                consumerCashback = goods.getTenThousandConsumerCashback();
            }
            salesCommissionDTO.setGroupPinReward(new BigDecimal(consumerCashback));
        }
        return salesCommissionDTO;
    }

    @Override
    public List<GroupBuyingSub> selectListByDateRange(LocalDate startDate, LocalDate endDate) {
        if (startDate.isAfter(endDate)) {
            throw new ServiceException("结束时间不能大于开始时间");
        }
        return baseMapper.selectList(new LambdaQueryWrapper<GroupBuyingSub>()
                .apply("DATE(create_time) BETWEEN '" + startDate + "' AND '" + endDate + "'"));
    }
}
